Original link
This article is written by my colleague, set up in conjunction with Express Webpack. The following is the text, later I will attach my interpretation
Express combined Webpack achieve HMR
Benpian file mainly about Express to achieve combined Webpack and front and rear ends of the heat development update, if you do not know webpack Recommended Reading
webpack official website documents
What
What is webpack dev server
Webpack dev server is a lightweight node.js express server, realize the real-time output webpack compiled code update. The rear end of the front end separation frequently used in the previous project development. However, this article should not talked about it.
webpack dev middleware
Webpack dev middleware is a middleware WebPack of. It is used to distribute Express in need WebPack compiled files. It can be used alone thermal overload completion code (hot reloading) function.
characteristic:
It does not write files on the hard disk, based entirely on memory implementation.
If a watch mode monitor code changes, automatically compiles Webpack, if the requested file compilation process Webpack, Webpack dev middleware request will be delayed until after the completion of the translation start again transmitting the compiled file.
webpack hot middleware
Webpack hot middleware Webpack it updated by subscribing to compile, after execution by HMR api webpack of these updates code modules pushed to the browser.
HMR
HMR That Hot Module Replacement Webpack is an important feature. It allows us to achieve our real-time update the code to the current page without refreshing the browser page by manually.
The principle HMR is application code in our development added the HMR Runtime, which is a module HMR client (browser client) for the development and communication server to receive updates. Webpack server job is the aforementioned hot middleware, it will compiled code update after json format to output to HMR Runtime will be described in more json dynamically updated by the appropriate code.
How
webpack Configuration
First introduced in webpack profile
var webpack = require('webpack');
var HotMiddleWareConfig = 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000'
module.exports = {
context: __dirname,
entry: [
// 添加一个和HotMiddleWare通信的客户端
HotMiddleWareConfig,
// 添加web应用入口文件
'./client.js'
],
output: {
path: __dirname,
publicPath: '/',
filename: 'bundle.js'
},
devtool: '#source-map',
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
// 在 webpack 插件中引入 webpack.HotModuleReplacementPlugin
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
};
webpack-hot-middleware example webpack.config.js
In our development environment is configured. getEntries is to automatically obtain an entry file and add webpack hot middle configuration according to our rules.
var webpack = require('webpack');
var path = require('path')
var merge = require('webpack-merge')
var baseConfig = require('./webpack.base')
var getEntries = require('./getEntries')
var publicPath = 'http://0.0.0.0:7799/dist/';
var hotMiddlewareScript = 'webpack-hot-middleware/client?reload=true';
var assetsInsert = require('./assetsInsert')
module.exports = merge(baseConfig, {
entry: getEntries(hotMiddlewareScript),
devtool: '#eval-source-map',
output: {
filename: './[name].[hash].js',
path: path.resolve('./public/dist'),
publicPath: publicPath
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"'
}
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new assetsInsert()
]
})
Express configuration
Express configuration mainly on four steps:
Introducing webpack profile and compilers generated webpack
The compiler is connected to webpack dev middleware
The compiler is connected to webpack hot middleware
The definition of express configuration
var http = require('http');
var express = require('express');
var app = express();
app.use(require('morgan')('short'));
// ************************************
// This is the real meat of the example
// ************************************
(function() {
// Step 1: 引入 webpack 的配置文件和 生成 webpack 的编译器
var webpack = require('webpack');
var webpackConfig = require(process.env.WEBPACK_CONFIG ? process.env.WEBPACK_CONFIG : './webpack.config');
var compiler = webpack(webpackConfig);
// Step 2: 将编译器挂载给 webpack dev middleware
app.use(require("webpack-dev-middleware")(compiler, {
noInfo: true, publicPath: webpackConfig.output.publicPath
}));
// Step 3: 将编译器挂载给 webpack hot middleware
app.use(require("webpack-hot-middleware")(compiler, {
log: console.log, path: '/__webpack_hmr', heartbeat: 10 * 1000
}));
})();
// 定义 express 配置
app.get("/", function(req, res) {
res.sendFile(__dirname + '/index.html');
});
app.get("/multientry", function(req, res) {
res.sendFile(__dirname + '/index-multientry.html');
});
if (require.main === module) {
var server = http.createServer(app);
server.listen(process.env.PORT || 1616, function() {
console.log("Listening on %j", server.address());
});
}
webpack-hot-middleware example server.js
Distinguish between development and production environments
Note that the definition of middleware webpack must be related to the definition of prior express router. Another point here is just server.js development environment used in the build environment, we do not need to reuse them. Therefore, our actual use need to distinguish between development and production environments by defining the environment variable
var NODE_ENV = process.env.NODE_ENV || 'production';
var isDev = NODE_ENV === 'development';
if (isDev) {
var webpack = require('webpack'),
webpackDevMiddleware = require('webpack-dev-middleware'),
webpackHotMiddleware = require('webpack-hot-middleware'),
webpackDevConfig = require('./build/webpack.config.js');
var compiler = webpack(webpackDevConfig);
app.use(webpackDevMiddleware(compiler, {
publicPath: webpackDevConfig.output.publicPath,
noInfo: true,
stats: {
colors: true
}
}));
app.use(webpackHotMiddleware(compiler));
routerConfig(app, {
dirPath: __dirname + '/server/routes/',
map: {
'index': '/',
'api': '/api/*',
'proxy': '/proxy/*'
}
});
var reload = require('reload');
var http = require('http');
var server = http.createServer(app);
reload(server, app);
app.use(express.static(path.join(__dirname, 'public')));
server.listen(port, function() {
console.log('App (dev) is now running on port ' + port + '!');
});
} else {
routerConfig(app, {
dirPath: __dirname + '/server/routes/',
map: {
'index': '/',
'api': '/api/*',
'proxy': '/proxy/*'
}
});
app.use(express.static(path.join(__dirname, 'public')));
app.listen(port, function() {
console.log('App (dev) is now running on port ' + port + '!');
});
}
supervisor
In the front we have achieved more than hot update the front of the file, but we modify the server file, does not make the Node automatically restart, so we use as a supervisor to monitor file modification event to automatically restart Node service.
supervisor requires global installation
npm install supervisor -g
After the installation is complete, we can use the command line
we write frequently used commands in the scripts package.json, after which only can be used with npm run xxx
"scripts": {
"dev": "export NODE_ENV=development && supervisor -w server,app.js app",
"build": "node build/build.js",
"start": "node app"
},
supervisor [options] <program>
supervisor -w server,app.js app
-w options is a configuration item, which is used to monitor changes in the specified directory or file can be used,
after separate, monitor multiple directories or files, this is the monitor of app.js server directory and the root directory will be changed to restart our Express entry file app.
My own interpretation
First, to explain his original code is difficult to explain a few points:
getEntries this unified approach is to load our own entrance file, in fact, the specific content of the article I mentioned earlier, is ordained, folders main.js directory is our entry file, ignoring all other reasons also said that, here again, the provisions die, simple, convenient and conducive to cooperation.
publicPath = var ' http://0.0.0.0:7799/dist/ '; here publicPath reasons and we usually configured Webpack of publicPath not the same, is able to recognize the absolute need Express addresses, because you project is greater than Webpack Express of.
routerConfig This method is a method of our own, the content of the article mentioned earlier, it is that I wrote a method used to load all the routes, so as not to repeat writing various reference. npm address
Note that export NODE_ENV = development, windows environment may fail, can be replaced by cross-env NODE_ENV = development
Secondly, said the reason to do so under
The article also mentioned earlier, our current overall front-end architecture is the use of Node do middle layer, then the problem is Node render layer will be higher than Webpack layer, and in many cases, do not necessarily use the SPA way, be compatible with the architecture, so it You need these configurations.
This configuration also solved a number of pain points in our development, a Node automatically re, hot update a file, combine basic you do not need to constantly manually refresh the browser, and can save the current state, which is key You can save a lot of time to improve development efficiency.
Of course there are pain points, for example, to more than a template file, and the file directory according to specifications, but for not rendering.