昨天半夜对自己手上一个比较老的项目产生了一些想法,决定从 Angular 4.x 升级到 Angular 8.x .

由于 Angular 的版本号飞快,Angular 6.x 的改动也比较激进,主要体现在构建上。

在 6.x 之前 CLI 支持 ng eject, 可以灵活修改 webpack.config.js 来构建自己的项目。但是 6.x 之后 Angular 不再支持 eject, 大概是由于 Angular 的定位是浏览器环境,出于安全考虑并没有让用户直接使用 Node 模块,因此用了 Angular 的 Electron 用户基本上原地爆炸。

也就是说 6.x 之后不再提供 eject 的方式让你可以直接修改 webpack。只能全部通过 angular.json 来配置项目。

解决方法

在官方仍然没有提供合适的解决方案时,可以通过一些曲线救国的方式临时解决问题。

前往文件:
node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js

在 91 行左右可以看到以下代码:

1
2
3
// ...
node: false;
// ...

这个决定了 webpack 不会加载 node 模块。因此我们可以通过把这一行改为:

1
2
3
// ...
node: { crypto: true, fs: 'empty', net: 'empty' },
// ...

上面代码会让 webpack 加载 crypto, fs, net 这几个 node 模块。
模块的加载方式参考 webpack 关于 node 有关的使用文档:https://webpack.js.org/configuration/node

补丁脚本

手动更改 node_modules 中的内容会有一些瑕疵,一旦重新执行安装,会导致更改过的内容被覆盖。因此我们可以通过写一个脚本在每次 npm install 或者 yarn 之后自动为我们更改。

  • 在你的项目目录下创建 tools/ng-webpack-patch.js,写入以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const fs = require("fs");
const config =
"node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js";

fs.readFile(config, "utf8", (err, data) => {
if (err) {
return console.log(err);
}

const result = data.replace(
/node: false/g,
"node: { crypto: true, fs: 'empty', net: 'empty' }"
);

fs.writeFile(config, result, "utf8", function(err) {
if (err) return console.log(err);
});
});
  • 在项目里的 package.json 下的 scripts 里添加 postinstall 命令:
1
2
3
4
5
6
7
8
9
{
// ...
"scripts": {
// ...
"postinstall": "node tools/ng-webpack-patch.js"
// ...
}
// ...
}

这样在每次执行 npm install 或者 yarn 之后,都会自动为我们执行 postinstall 中的脚本,修改 webpack-configs/browser.js.