webpack 构建 支持 ES6/7 的 node 服务开发

1. 准备工作

安装 node 环境并创建项目 npm init

安装 webpacknodemonconcurrentlyexpress

npm install --save-dev webpack nodemon concurrently
npm install --save express

webpack 为最新版本,本身支持 ES6 语法。

2. 服务端程序

server.js

import express from 'express';
import test from './js/console.js';

let app = express();
let PORT = 3000;

app.get('/', (req, res) => {
  res.send('Hello!');
});

let server = app.listen(PORT, function () {
  let host = server.address().address;
  let port = server.address().port;

  console.log('Server is listening at http://%s:%s', host, port);
});

console.js

export default function test () {
  console.log('I am console');
}

3. webpack 配置

3.1. 开发配置

webpack.dev.js

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: [
    /* 轮询文件内容 */
    'webpack/hot/poll?1000',
    path.resolve(__dirname, 'server.js')
  ],

  output: {
    filename: 'backend.js',
    path: path.resolve(__dirname, 'dist')
  },

  /* 指明编译方式为 node */
  target: 'async-node',

  plugins: [
    /* HMR plugin */
    new webpack.HotModuleReplacementPlugin(),

    /* 当 HMR 替换时在浏览器控制台输出对用户更友好的模块名字信息 */
    new webpack.NamedModulesPlugin()
  ]
};

3.2. 生产配置

webpack.prod.js

const path = require('path');
const webpack = require('webpack');
const fs = require('fs');

const nodeModules = {};

fs.readdirSync('node_modules')
  .filter( (catalogue) => {
    return ['.bin'].indexOf(catalogue) === -1;
  })
  .forEach( (mod) => {
    nodeModules[mod] = 'commonjs ' + mod;
  });

module.exports = {
  entry: [
    path.resolve(__dirname, 'server.js')
  ],

  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  /* 告知 webpack 为 node 服务,并忽略 externals 中的模块 */
  target: 'node',
  externals: nodeModules,

  /* __dirname 和 __filename 指向原始地址 */
  context: __dirname,
  node: {
    __filename: false,
    __dirname: false
  }
};

4. 运行配置

package.json

...

"scripts": {
    "dev-webpack": "npx webpack --config webpack.dev.js --watch &",
    "dev-nodemon": "npx nodemon dist/backend.js &",
    "dev": "npx concurrently \"npm run dev-webpack\" \"npm run dev-nodemon\"",
    "prod": "npx webpack --config learn/graphql/webpack.prod.js"
  },

...

5. 运行程序

开发,可以实现后台程序 HMR 热更新:

npm run dev

生产,打包后台程序:

npm run pro

6. 总结

优点:

  • 前端和后台的构建工具统一,方便维护和持续集成。

缺点:

  • 热更新开发过程会有 hot-update.js 和 hot-update.json 的缓存文件在 output 目录,暂时没发现如何消除。
  • 开发模式下,如果 webpack 没有构建好打包程序, nodemon 命令执行无法找到构建代码。

7. 优化 level-1

7.1. 工具

rimraf 删除文件工具。
webpack-shell-plugin webpack shell 执行工具。

npm install --save-dev rimraf webpack-shell-plugin

7.2. 配置更改

webpack.dev.js

  • 删除文件轮询,热更新过程中控制台会报错,但不影响程序正常执行。
  • 新增 webpack-shell-plugin,在 webpack 构建完成后在启动 nodemon 服务。
const path = require('path');
const webpack = require('webpack');

const WebpackShellPlugin = require('webpack-shell-plugin');

module.exports = {
  entry: [
    path.resolve(__dirname, 'server.js')
  ],

  output: {
    filename: 'backend.js',
    path: path.resolve(__dirname, 'dist')
  },

  /* 指明编译方式为 node */
  target: 'async-node',

  plugins: [
    /* HMR plugin */
    new webpack.HotModuleReplacementPlugin(),

    /* 当 HMR 替换时在浏览器控制台输出对用户更友好的模块名字信息 */
    new webpack.NamedModulesPlugin(),

    new WebpackShellPlugin({
      onBuildEnd: [
        'npx nodemon ' 
        + path.resolve(__dirname, 'dist')
        + '/backend.js --watch '
        + path.resolve(__dirname, 'dist')
      ]
    })
  ]
};

package.json

在执行构建前先删除 hot-update 缓存文件,包括生产模式。

...

"scripts": {
    "dev": "npx rimraf dist && npx webpack --config webpack.dev.js --watch",
    "prod": "npx rimraf dist && npx webpack --config learn/graphql/webpack.prod.js"
  },

...

8. 优化 level-2

修改 webpack.dev.js:

...

  output: {
    ...
    hotUpdateChunkFilename: '',
    hotUpdateMainFilename: ''
  },

...

9. 优化 level-3

webpack.dev.js:

  • 增加忽略 externals 中的模块
  • webpack update 临时文件固定,如果命名为 '',会报错
  • nodemon 监控文件仅为服务器入口程序 server.bundle.js,并添加 --exitcrash 选项
  • 重新声明上下文环境,为后续配合前端框架做准备
const path = require('path');
const webpack = require('webpack');
const fs = require('fs');

const WebpackShellPlugin = require('webpack-shell-plugin');

const WEBPACK_SERVER_JS_NAME = 'server.bundle.js';

const nodeModules = {};

fs.readdirSync('node_modules')
  .filter( (catalogue) => {
    return ['.bin'].indexOf(catalogue) === -1;
  })
  .forEach( (mod) => {
    nodeModules[mod] = 'commonjs ' + mod;
  });

module.exports = {
  entry: [
    path.resolve(__dirname, 'src/server.js')
  ],

  output: {
    filename: WEBPACK_SERVER_JS_NAME,
    path: path.resolve(__dirname),
    hotUpdateChunkFilename: 'hot-update.js',
    hotUpdateMainFilename: 'hot-update.json'
  },

  /* 告知 webpack 为 node 服务,并忽略 externals 中的模块 */
  target: 'node',
  externals: nodeModules,

  plugins: [
    /* HMR plugin */
    new webpack.HotModuleReplacementPlugin(),

    /* 当 HMR 替换时在浏览器控制台输出对用户更友好的模块名字信息 */
    new webpack.NamedModulesPlugin(),

    new WebpackShellPlugin({
      onBuildEnd: [
        Array(
          'npx', 
          'nodemon', 
          path.resolve(__dirname, WEBPACK_SERVER_JS_NAME),
          '--watch',
          path.resolve(__dirname, WEBPACK_SERVER_JS_NAME),
          '--exitcrash'
        ).join(' ')
      ]
    })
  ],

  /* __dirname 和 __filename 指向原始地址 */
  context: __dirname,
  node: {
    __filename: false,
    __dirname: false
  }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值