Include for use, modification and reprint have been obtained Tencent Cloud To grant authorization
Preface
In web front-end development, we will use the Watch module of Grunt, Gulp and Webpack tools to monitor file changes. What should the server do? In fact, file changes can still be monitored with the help of build tools, but we also need to automatically restart the service or hot overload. This article will introduce three common methods.
Plan 1: fs.watch
Using node's native fs.watch method to monitor file changes, the so-called "hot overload" is just to clear the file cache in memory in time. Examples are as follows:
const fs = require('fs'), path = require('path'), projectRootPath = path.resolve(__dirname, './src'); const watch = project => { require('./src'); // Start APP and automatically retrieve src/index.js try { // Listen Folder fs.watch(project, { recursive: true }, cacheClean) } catch(e) { console.error('watch file error'); } } // Clear Cache const cacheClean = () => { Object.keys(require.cache).forEach(function (id) { if (/[\/\\](src)[\/\\]/.test(id)) { delete require.cache[id] } }) } // Start development mode watch(projectRootPath);
Note: When referring to middleware in the server entry file src/index.js, a layer of functions is needed and modules are introduced in the way of require to clear the cache. For example:
// Introducing middleware or controllers app.use(async (ctx, next) => { await require('./controllers/main.js')(ctx); }); // Or introduce routing app.use(async (ctx, next) => { await require('./router').routes()(ctx, next) })
Solution 2: Application of Process Manager
Take PM2 as an example, supervisor, forever and other similar process management tools have the same characteristics, which are not discussed here.
PM2 is a Node application process manager with load balancing function. It has the watch configuration item, which is used to monitor the changes of the application directory and restart immediately when the changes occur. See: Auto restart apps on file change . He is a real restart, not a hot replacement.
Disadvantage: PM2 does not provide an elegant way to tell users when to restart or kill processes.
The following is a simple PM2 configuration (development environment) start.js to start the process node start.js.
const pm2 = require('pm2'); pm2.connect(function(err) { if (err) { console.error(err); process.exit(2); } pm2.start({ "watch": ["./app"], // Open watch mode and listen for changes under app folder "ignore_watch": ["node_modules", "assets"], // Documents that ignore listening "watch_options": { "followSymlinks": false // Symbolic links are not allowed }, name: 'httpServer', script: './server/index.js', // APP Entry exec_mode: 'fockMode', // FokModel is recommended in development mode instances: 1, // Only one CPU is enabled max_memory_restart: '100M' // Restart APP when 100M of memory is occupied }, function(err, apps) { pm2.disconnect(); // Disconnects from PM2 if (err) throw err }); });
Every time the file is modified and saved (Ctrl+S), a black box flashes, indicating that the application has been restarted successfully.
Scheme 3: chokidar + babel
Chokidar is a layer of encapsulation for fs.watch/fs.watchFile/fsevents. Its advantages include resolution (from chokidar documents):
1. File names cannot be obtained under OS X.
2. Sublime can't get modification events after modifying files under OS X.
3. Modifying the file will trigger two events.
4. Document recursive monitoring is not provided.
5. High CPU utilization rate;
6,...
The reason for using babel here is to support the latest js syntax, including ES2017, Stage-x, and module syntax such as import/export default.
The following provides a complete listen overload configuration file, and explains its functions and significance through comments.
const projectRootPath = path.resolve(__dirname, '..'), srcPath = path.join(projectRootPath, 'src'), // source file appPath = path.join(projectRootPath, 'app'), // Compiled Output Folder devDebug = debug('dev'), watcher = chokidar.watch(path.join(__dirname, '../src')) // Start chokidar to listen for file changes watcher.on('ready', function () { // babel Compiler Folder Directory babelCliDir({ outDir: 'app/', retainLines: true, sourceMaps: true }, [ 'src/' ]) // compile all when start require('../app') // Start APP (compiled file) // Adding listening methods watcher // Documentation Added .on('add', function (absPath) { compileFile('src/', 'app/', path.relative(srcPath, absPath), cacheClean) }) // File modification .on('change', function (absPath) { compileFile('src/', 'app/', path.relative(srcPath, absPath), cacheClean) }) // File deletion .on('unlink', function (absPath) { var rmfileRelative = path.relative(srcPath, absPath) var rmfile = path.join(appPath, rmfileRelative) try { fs.unlinkSync(rmfile) fs.unlinkSync(rmfile + '.map') } catch (e) { devDebug('fail to unlink', rmfile) return } console.log('Deleted', rmfileRelative) cacheClean(); //Clear Cache }) }) // Dynamic compilation of files function compileFile (srcDir, outDir, filename, cb) { const outFile = path.join(outDir, filename), srcFile = path.join(srcDir, filename); try { babelCliFile({ outFile: outFile, retainLines: true, highlightCode: true, comments: true, babelrc: true, sourceMaps: true }, [ srcFile ], { highlightCode: true, comments: true, babelrc: true, ignore: [], sourceMaps: true }) } catch (e) { console.error('Error while compiling file %s', filename, e) return } console.log(srcFile + ' -> ' + outFile) cb && cb() // Usually to clear the cache } // Clear Cache function cacheClean () { Object.keys(require.cache).forEach(function (id) { if (/[\/\\](app)[\/\\]/.test(id)) { delete require.cache[id] } }) console.log('App Cache Cleaned...') } // Withdrawal of listening procedure process.on('exit', function (e) { console.log('App Quit') })
Note: In order to make the cache invalid, we also need to wrap a layer of functions in use and introduce routing in a require way.
app.use(async (ctx, next) => { await require('./router').routes()(ctx, next) })
Solution 4: Developing plug-ins
Noemon and node-dev are plug-ins for node.js development edition, providing a simple and easy-to-use development environment. In the case of nodemon, global or local installation is possible
npm install nodemon -g
Then the development process is started by nodemon. / server. JS localhost 8080. Independent, simple, easy to use!
See: remy/nodemon
Sum up
Each method has different applicable scenarios. If you want to try the latest grammar, recommend scheme 3; if you want to be simple and fast, scheme 2 is a good choice.
Is that over?
What if I want to use the latest grammatical features and need to be as simple as PM2? babel build tools (such as webpack) are no stranger to each front-end development, and a PM2 is enough to solve all the problems.
Links to the original text: https://www.qcloud.com/community/article/476280