[今晚我想来点 Express 佐 MVC 分层架构] DAY 27 - 用 Webpack 打包 Express

Webpack 是什麽?

https://ithelp.ithome.com.tw/upload/images/20201012/20119338bEHdErt8M8.png
图片来源

Webpack 是一个打包工具,经常用於前端领域,能够将各个依赖的档案进行 bundle, 更提供了预处理的功能,使 sassES6 等被翻译成浏览器看得懂的样子。

为什麽要用 Webpack?

事实上後端与前端不同,大部分情况下 後端是没有打包的必要,也就是说使用 Webpack 打包後端并不是必要条件,但我会特地写一篇关於 Webpack 打包 Express 是有原因的,请大家先试着建置 production 版本并跑起来看看吧!

要记得先完善 production.env 的内容呦!

npm start

咦?怎麽会出错?
https://ithelp.ithome.com.tw/upload/images/20200916/20119338Kk3fNpqqxI.png

这个 secret 有点眼熟,没错,就是 JWT 要使用的值,这部分我们是将它写成环境变数去读取,表示环境变数的读取有问题,可以发现编译後的档案不包含 environments 下的所有档案,原因是 TypeScript Compiler 本身只编译 TS ,那要怎麽把环境变数档搬过去呢?最土法炼钢的方法就是写脚本复制一份到 dist 资料夹下,但还有另一条路可以走,就是使用 Webpack

预处理环境变数

Webpack 对环境变数的处理 不是 将环境变数档的内容放入环境变数来 读取,而是将使用到环境变数档内容的程序码片段 抽换 成这些环境变数的值,什麽意思呢?以 JWT_SIGN 这个环境变数为例,以下是 JWT_SIGN 的范例内容:

JWT_SIGN=zxcdsaqwerfv

在没有经过预处理的情况下是透过 process.env.JWT_SIGN 去读取,并从记忆体中取得 zxcdsaqwerfv 这串字;经过预处理後,是会把程序码中出现 process.env.JWT_SIGN 的部分直接变成 zxcdsaqwerfv 这串字,这样的好处是 不用一直搬移档案 ,也 不需要花时间与空间去读取环境变数

开始打包吧!

先透过 npm 安装 Webpack 与 Webpack CLI:

npm install webpack webpack-cli --save-dev

安装完毕後,还需要再安装 ts-loader,原因是要让 Webpack 知道该以什麽样的方式去读取档案并编译:

npm install ts-loader --save-dev

如果不希望把 node_modules 这个黑洞 一起打包的话,强烈建议安装 webpack-node-externals 这个套件:

npm install webpack-node-externals --save-dev

一切准备就绪!在专案目录下新增 webpack.config.js,里面的内容即为 Webpack 的配置:

const path = require('path');
const webpack = require('webpack');
const dotenv = require('dotenv');
const nodeExternals = require('webpack-node-externals');

module.exports = (env, argv) => {

  // 取得环境变数档的内容,并依照 mode 来切换模式
  const params = dotenv.config({ path: path.resolve(__dirname, `./src/environments/${argv.mode}.env`) }).parsed;
  
  // 将环境变数的设置写入 Object 中,以方便後续调用
  const processEnv = {};
  Object.keys(params).forEach(key => processEnv[`process.env.${key}`] = JSON.stringify(params[key]));

  return {
    entry: './src/index.ts',               // 载入点
    target: 'node',                        // 使用 node
    externals: [
      nodeExternals()                      // 排除 node_modules
    ],
    module: {
      rules: [
        {
          test: /\.ts$/,                  // .ts 的档案用 ts-loader 读取
          use: 'ts-loader',
          exclude: /node_modules/
        }
      ]
    },
    resolve: {
      extensions: ['.ts', '.js']         // 补足 import 档案的结尾
    },
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    plugins: [
      new webpack.DefinePlugin(processEnv)  // 设置环境变数
    ]
  }
};

与 nodemon 结合

在开发过程中一定会有热重载的需求,也就会想起我们的好朋友 nodemon,但要如何跟 Webpack 整合呢?就要安装 nodemon-webpack-plugin

npm install nodemon-webpack-plugin --save-dev

并在 webpack.config.jsplugins 下使用:

plugins: [
  new webpack.DefinePlugin(processEnv),
  new NodemonPlugin()
]

修改 tsconfig.json

由於有些操作权已经交给 Webpack,这边就可以把部分 TypeScript 的配置关闭:

{
  "compilerOptions": {
    "incremental": true,               // 启用增量编译
    "target": "ES2017",                // 编译成指定的 JavaScript 版本
    "module": "commonjs",              // 指定编译成何种模组
    "declaration": false,              // 产生 '.d.ts' 档
    "sourceMap": false,                // 产生 '.map' 档
    "rootDir": "./src",                // 载入点的位置
    "removeComments": true,            // 移除注解
    "strict": true,                    // 采用严格模式
    "baseUrl": "./src",                // 指定汇入档案的基准路径
    "esModuleInterop": true,           // 兼容模组
    "experimentalDecorators": true,    // 启用装饰器
    "emitDecoratorMetadata": true      // 提供装饰器 metadata
  },
  "include": ["src/**/*.ts"],          // 纳入编译范围
  "exclude": ["node_modules", "dist"]  //不纳入编译范围
}

修改 package.json

我们要来调整 npm script 的配置,如下:

"scripts": {
  "start": "NODE_ENV=production node ./dist/main.bundle.js",
  "start:dev": "webpack --mode=development --watch",
  "start:prod": "webpack --mode=production --watch",
  "build": "webpack --mode=production"
}

接着只要视情况使用就可以罗!

小结

用 Webpack 打包後端虽然不是必要,但也是种选择,我认为能够稳定、方便开发与容易维护才是最重要的,要不要使用这个方法全看需求而定,各位有什麽看法呢?欢迎在下面讨论!


<<:  菜鸡用 Phaser 拾起童年游戏 29

>>:  [Android 开发经验三十天]D29一小画家小问题跟改善方法

前言与安装

为何想要一台 NAS? 备份档案,作为家里的网路磁碟机 当作小型服务器跑应用程序: 软件工程师手贱心...

Day 24:霍夫曼编码(Huffman coding)

这回写到的霍夫曼编码是在Algorithms Illuminated Part 3: Greedy ...

Day27:质数判定法(Primality Test)

质数(Prime number) 在国中时有学过质数,质数除了1和本身之外,没有其他因数的大於1的自...

Day11-React 表单验证篇-不使用 hook 或第三方函式库

React 的表单验证篇总共会三篇,这篇我们会自己手刻一个验证输入值是否合法的表单,而在後面两篇文章...

[第四只羊] 迷雾森林建筑工事 III 透过Jumpstarter建立新专案

天亮了 昨晚是平安夜 关於迷雾森林故事 洛神降临 图片来源 她就是洛神啊 以前只听过爸妈说过 这还是...