工作记录—webpack编译数据模型库

业务场景

在主项目中有许多数据模型,包括Interface,Model,Code等。
定义好数据模型后,在开发过程中,IDE会有代码提示,并且进行数据类型检查,不存在的字段在编辑时,会有报错提示,这给coding带来了便利,比如:避免了因拼写错误造成的Bug。
除了主项目之外,还有若干个项目共用同一套数据模型。
目前的方案是:

  1. 在库A写代码(typescript)更新数据
  2. 完成后 更改package.json 的版本号
  3. npx tsc命令 将 .ts 转译为 对应的(浏览器可识别的) js 和.d.ts, 并且build到库B
  4. 库B中打标签(即package.json中的版本号), npm push –tags 标签推送远端
  5. 推送库A 的代码

In a word, 库A coding, 编译并build到库B。使用时,npm 仅安装库B。
npm i git+https://bitbucket.org/xxx/B.git#3.xx.x

新的需求是:

通过webpack自动编译,并打包到同一个库内,不需要同时维护两个库。

方案步骤

安装相关依赖

webpack 中转译ts为js的插件为ts-loader
npm i ts-loader typescript webpack webpack-cli
以上命令默认安装latest版本

配置 webpack.config.js

在项目根目录,创建 webpack.config.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

const path = require('path');
module.exports = {
mode: 'development',
entry: './index.ts',
output: {
// 打包后 输出的文件名
filename: 'index.js',
// 打包后 导出文件的路径
path: path.resolve(__dirname, './lib'),
library: {
name: 'revoposCommonRepo',
type: 'umd',
},
},
resolve: {
extensions: [".ts", ".tsx", ".js"]
},
module: {
rules: [
{
// 正则匹配规则: `.ts` or `.tsx` 会被 ts-loader 处理
test: /\.ts$/,
// node_modules里的文件不编译
exclude: /node_modules/,
// 使用ts-loader进行预处理
loader: 'ts-loader'
}
]
},
plugins: []
}

配置 tsconfig.json

同样在根目录下创建。
此文件用来配置 TypeScript 编译器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

{
"compilerOptions": {
"target": "es5", //指定编译之后的版本目录
"module": "commonjs", //指定要使用的模板标准
"declaration": true, //是否在编译时生成相应.d.ts声明文件
"outDir": "./lib", //指定输出文件夹
"strict": true,
},
"exclude": [ //要排除的,不编译的文件
"node_modules",
"lib",
],
}

使用 uglifyjs-webpack-plugin 压缩js文件

跑命令,安装插件:

npm i -D uglifyjs-webpack-plugin

在webpack.config.js中添加:

一、 引入 uglifyjs-webpack-plugin

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

二、 添加 optimization 配置项

1
2
3
4
5
6
7
8
9
10
11
12

optimization: {
minimize: true,
minimizer: [new UglifyJsPlugin({
uglifyOptions: {
output: {
comments: false //代码中的注释不导出
}
}
})],
},

使用 uglifyjs-webpack-plugin 压缩文件后,build出的js文件大小由 131kb => 111kb

修改package.json 中script的配置,使其通过webpack打包

1
2
3
4
5

"scripts": {
"build": "webpack --progress --config webpack.config.js"
},

打包

跑命令 npm run build
打包完成后,项目结构如下

avatar

如何使用

  1. 安装
    跑命令npm i git+https://bitbucket.org/xxx/xxx.git#3.xx.xx
  2. 在需要使用的文件中引用
    import { IConfig } from 'xxx/lib';
  3. 使用
    举例说明
1
2
3
4
5

let config = await this.config_svp.Get() as IConfig;
config.shop_id = 1;
config.lang = 'en';

使用 npm link

由于在包开发过程中,需要不断调试。
一修改代码,就推到远端。再在需要使用的项目中重新 npm i,这样的测试方法是不现实的。
于是 考虑使用 npm link,
使得数据模型包在修改代码并保存后,即可在应用的项目中,实时更新。
假设, 数据模型库的package.json 中的name 为 data-repo,
现在,要在main-repo中使用。

  1. 进入data-repo项目,
  2. npm link
  3. 执行命令后,data-repo会根据package.json上的配置,被链接到全局
  4. 进入main-repo项目
  5. npm link data-repo 这样data-repo会被映射到 main-repo的node_module下
  6. 若不需要此链接了,则 npm unlink data-repo 取消映射关系

遇到了哪些问题

一、 依赖包版本冲突

一顿操作配置,打包,安装,替换引用后,以为万事俱备。
serve 命令行 跑项目 根本打不开
直接大片红色报错
第一行是:
ERROR in node_modules/@types/node/assert.d.ts(3,68): error TS1144: '{' or ';' expected.

经过chrome搜索,
论坛上有若干热心网友的若干个解决提案
宗旨主要是typescript版本冲突问题。

问题定位
数据模型项目 data-repo 的typescript 版本为 4.6.3, webpack,webpack-cli,ts-loader也均为相应的latest version
主项目main-repo 的 typescript 版本为2.8.3

解决方案
由于typescript,webpack,webpack-cli,ts-loader都装在了dependencies,
现在重新安装: npm i 命令行加 -D
安装在 devDependencies下。

搞定。

二、 依赖缺失

在主项目main-repo 中删除了原有的数据模型包old-data-repo,package.json中移出对应配置,并将项目中对它的引用通通替换为新的数据模型包data-repo。
ionic serve 运行起项目之后,用到数据模型的若干接口正常运行,各种http交互一切顺利。

但进入某个特定界面,会报错:
can’t find module old-data-repo
经检查,在项目中已经没有使用引用注册过任何old-data-repo。

于是去chrome 查看报错信息,
点进去Js文件,发现报错位置是main-repo依赖的包core-repo。
core-repo是公司自己开发的工具包,用来处理一些多个项目共有的逻辑:
比如 折扣计算,计税,服务费计算等等。
而在core-repo中,引用了old-data-repo。

而在报错的特定界面逻辑中,调用了core-repo的限制日历跨越天数的方法。
于是将main-repo中该方法的调用注释掉, import core-repo也注释掉。
重新 serve 发现项目正常运行没有问题,
但特定页面中限制选择时长的功能not working any more.

由此, 可定位 问题出在

main-repo 依赖 core-repo, core-repo 依赖 old-data-repo。
由于要测试,我手动删除了old-data-repo,
故core-repo 的依赖不存在 所以报错。

解决方法

删除core-repo,
重新 npm i core-repo@3.xx.xx
此时 npm 自动会根据 core-repo 的package 安装它所需的正确版本的依赖包到main-repo 的node_modules。

serve 跑起来, 没有任何报错, 日历选择日期恢复跨度限制。

三、 WEBPACK_IMPORTED_MODULE 报错

在使用到data-repo的地方(基本上就是90%的页面),
报错如下
ERROR Error: Uncaught (in promise): TypeError: __WEBPACK_IMPORTED_MODULE_0_jdata_lib__.InvoiceModel is not a constructor

经过和google search 的友好交流:
得知webpack.config.js 的配置少了两行。
以下为完整配置代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
mode: 'development',
entry: './src/index.ts',
output: {
filename: 'index.js',
path: path.resolve(__dirname, './lib'),
// 这里的library加上后,不会再报错
library: {
name: 'revoposCommonRepo',
type: 'umd',
},
},
resolve: {
extensions: [".ts", ".tsx", ".js"]
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
loader: 'ts-loader'
}
]
},
plugins: [],
optimization: {
minimize: true,
minimizer: [new UglifyJsPlugin({
uglifyOptions: {
output: {
comments: false
}
}
})],
},
}

四、无法写入文件.d.ts

  • 问题:
    vscode 编译报错: 无法写入.d.ts 因为会覆盖
  • 解决方法:
    在tsconfig.json 中:
    配置outDir 并在exlucde中添加需要排除的文件。
    设置allowJs为false或删除该行。

五、npm i git+https 无响应

  • 问题:
    npm 包 from git url 失败,
  • 解决方法:
    修改命令 npm i git+https://git@bitbucket.org/xxx/xxx.git
    npm i git+https://bitbucket.org/xxx/xxx.git
查看评论