Original address: marxjiao.com/2018/04/10/…

Learning Node.js, here is how to build a typescript-based Node development environment using WebPack.

Essential functionality for the entire environment

A good development environment allows developers to focus on the code and not on anything else. Here are some of the necessary conditions.

  1. A single command can start the project.
  2. A command can package items.
  3. Code changes can be updated automatically at development time, preferably hot, rather than restarting the service, in preparation for later debugging with front-end code.
  4. You can debug using an editor or chrome. I’m used to vscode.

Basic Construction idea

Use TS globally, including scripts, webpack configuration files. NPM is used to call the TS script, which is executed using TS-Node, and the TS script is used to call the WEBpack API to package the build file.

npm scipts -> start-dev.ts -> webpack(webpackConfig)

Here’s why you use TS scripts to call webpack instead of writing webpack commands directly in NPM scripts. My idea is All In Typescrpt, try to use TS instead of JS, and use the Node API of Webpack to easily write webPack configuration In TS. Another advantage of this approach is that the webPack configuration can be written dynamically, generating the desired configuration based on the parameters passed in.

The selection

So far the selection of the project has been very clear.

  • TypescriptThe main language used by the project adds enhanced type support for front-end development and can avoid many problems in the coding process.
  • KoaIt is widely used. No additional functionality, middleware plug and play.
  • WebpackPackage tools, hot loading in development.
  • ts-nodeUsed to execute ts scripts directly.
  • start-server-webpack-pluginThe key webpack plugin can launch the service directly after compilation, and supports hot loading in Signal modewebpack/hot/signalVery good.

Environment set up

Let’s start by writing a simple Web server in Koa and then build the environment for that server.

Project code

Create a new server/app.ts file. This file is used to create a KOA app.

import * as Koa from 'koa';

const app = new Koa();

app.use(ctx => {
    ctx.body = 'Hello World';
});

export default app;
Copy the code

We need another file to start the server and listen for server/app.ts changes to hot load the project.

The new server/server. Ts

import * as http from 'http'; import app from './app'; // app.callback() returns a function that creates a server through http.createserver, similar to Express and connect. let currentApp = app.callback(); Const server = http.createserver (currentApp); server.listen(3000); / / heat load if (module. Hot) {/ / listen/app. Ts module. Hot. Accept ('. / app. Ts' () = > {/ / if there is a change, RemoveListener ('request', currentApp); currentApp = app.callback(); server.on('request', currentApp); }); }Copy the code

Compile the configuration

Before writing the WebPack configuration, let’s write down the TS configuration and the Babel configuration.

Typescript configuration

This is the configuration that webPack uses to compile code, and the configuration that TS-Node uses to run scripts will be described later. Let’s create config/tsconfig.json:

"Module ": "es2015", "noImplicitAny": true, "sourceMap": true, "moduleResolution": "node", "isolatedModules": true, "target": "es5", "strictNullChecks": true, "noUnusedLocals": true, "noUnusedParameters": true, "inlineSources": false, "lib": ["es2015"] }, "exclude": [ "node_modules", "**/*.spec.ts" ] }Copy the code

Babel configuration

Babelrc, “modules”: false is important, tree shaking, HMR depends on it.

{
  "presets": [["env", {"modules": false}]]
}
Copy the code

Webpack configuration

Typically, you need to prepare two webPack configurations, one for development and one for distribution. As mentioned earlier, packaging using the WebPack API makes it possible to create webPack configurations on the fly. So here we write a WebpackConfig class that generates the configuration of different environments based on the parameters when creating the instance.

The difference between development and release environments

First of all, the modes of the two environments are different. The development environment is Development, while the release environment is production. More information about mode can be found in the Webpack documentation.

The development environment requires hot loading and startup services. The entry needs to be configured with ‘webpack/hot/ Signal ‘. Use webpack-node-externals to package ‘webpack/hot/ Signal ‘into the code. Add HotModuleReplacementPlugin, use the start – server – webpack – the plugin to start the service and open the heat load.

Webpack configuration content

Now let’s write down the WebPack configuration. The key points are in the comments.

Create a new file config/ webpack.config.ts.

import * as path from 'path'; import * as StartServerPlugin from "start-server-webpack-plugin"; import * as webpack from 'webpack'; import * as nodeExternals from 'webpack-node-externals'; import {Configuration, ExternalsElement} from 'webpack'; Class WebpackConfig implements Configuration {// Node environment target: Configuration['target'] = "node"; Mode: Configuration['mode'] = 'production'; // Entry = [path.resolve(__dirname, '../server/server.ts')]; output = { path: path.resolve(__dirname, '.. /dist'), filename: "server.js" }; Externals: ExternalsElement[] = []; // loader module = {rules: [{test: /\.tsx?$/, use: [// TSC: Babel {loader: 'babel-loader',}, {loader: 'ts-loader', options: {// Speed up transpileOnly: true, // Specify a specific TS compilation configuration to distinguish the script's TS configuration configFile: path.resolve(__dirname, './tsconfig.json') } } ], exclude: /node_modules/ }, { test: /\.jsx?$/, use: 'babel-loader', exclude: /node_modules/ } ] }; resolve = { extensions: [".ts", ".js", ".json"], }; / / development environment also use NoEmitOnErrorsPlugin plugins = [new webpack. NoEmitOnErrorsPlugin ()]; Constructor (mode: Configuration['mode']) {constructor(mode: Configuration['mode']) { this.mode = mode; If (mode === 'development') {// Add webpack/hot/signal to update this.entry.push('webpack/hot/signal'); This.externals. push(// add webpack/hot/signal to externals ({whitelist: ['webpack/hot/signal']})); Const devPlugins = [/ / used to hot update new webpack HotModuleReplacementPlugin (), / / start the service new StartServerPlugin ({/ / start the file name: NodeArgs: ['--inspect']}),] this.plugins.push(... devPlugins); } } } export default WebpackConfig;Copy the code

Compile the script

Using TS-Node to launch the script requires the new tsconfig.json, which is compiled to run in Node.

Create tsconfig.json in the project root directory:

{"compilerOptions": {// For node environment to run directly "module": "commonjs", "noImplicitAny": true, "sourceMap": true, "moduleResolution": "node", "isolatedModules": true, "target": "es5", "strictNullChecks": true, "noUnusedLocals": true, "noUnusedParameters": true, "inlineSources": false, "lib": ["es2015"] }, "exclude": [ "node_modules", "**/*.spec.ts" ] }Copy the code

To develop the script

Start the development script, scripts/start-dev.ts:

import * as webpack from 'webpack'; import WebpackConfig from '.. /config/Webpack.config'; Const devConfig = new WebpackConfig('development'); Watch ({aggregateTimeout: 300}, (err: Error) => {console.log(err); });Copy the code

Add it in package.json

"scripts": {
    "dev": "rm -rf ./dist && ts-node ./scripts/start-dev.ts"
},
Copy the code

After executing yarn dev, we can see that the project is started:


Command line output


Browser display:




Browser display

Modify server/app. Ts


import * as Koa from 'koa';

const app = new Koa();

app.use(ctx => {
-   ctx.body = 'Hello World';
+   ctx.body = 'Hello Marx';
});

export default app;

Copy the code

You can see the command line output:




Command line output after updating code

Refresh the browser:




Browser display

You can see that the hot update has taken effect.

Publish the package script

New package script scripts/build.ts:

import * as webpack from 'webpack'; import WebpackConfig from '.. /config/Webpack.config'; const buildConfig = new WebpackConfig('production'); webpack(buildConfig).run((err: Error) => { console.log(err); });Copy the code

Add build command to package.json:

"scripts": {
+   "build": "rm -rf ./dist && ts-node ./scripts/build.ts",
    "dev": "rm -rf ./dist && ts-node ./scripts/start-dev.ts"
},
Copy the code

Run YARN Build to see dist/server.js. This is the output of our project. Node_modules dependencies are included in node_modules dependencies.

At this point the entire environment setup process is complete.

Full project code MarxJiao/ webpack-Node

conclusion

This project focuses on hot loading and All In Typescript.

1. Why is back-end code hot loaded?

To make it easier to package the front-end code with webPack middleware, you don’t have to recompile the front-end code without restarting the back-end services, which can be time-consuming. In subsequent use, the process would look something like this

Start-dev. ts -> Server -> Server code -> Webpack middleware -> front-end code

This ensures that development starts with only one entry and both ends are hot loaded.

2. Key points of hot loading

  • Webpack configurationmode: 'development'In order toNamedModulesPluginThe plug-in
  • Webpack configuration entry: ‘Webpack /hot/ Signal’
  • Pack ‘webpack/hot/signal’ into code: nodeExternals({whitelist: [‘webpack/hot/signal’]})
  • useHotModuleReplacementPlugin
  • Start – server – webpack – plugin configurationsignal: true
  • Babel configuration"modules": false
  • Tsconfig. Json configuration"module": "es2015"
  • Start the server with a separate file, listen for hot loaded files,server/server.ts

3. tsconfig

The tsconfig used by TS-Node to run scripts is different from the tsconfig used by TS-Loader to package code.

Ts-node uses config to compile the code directly in TSC and run it in Node. Import is not allowed in earlier versions of Node 8.x, so modules use CommonJS.

Webpack-wrapped code is hot loaded using es Module, in this case using ES2015.

The resources

  • Hot reload all the things!
  • How to HMR on server side?
  • Node.js Web application code hot update alternative ideas
  • Don’t use nodemon, there are better ways!
  • Webpack does node.js code hot replacement, the first step