频道
bg

前端工程化总结

coding四月 21, 20161mins
Frontend

概念H1

工程化需要模块、打包等过程。Java中模块、打包通常是有maven、gradle这样的打包工具来实现,Javascript对应的就是webpack。而编译分别对应的则是javac和babel、swr、tsc。

MonorepoH1

WorkspaceH2

  • yarn、npm的workspace支持多模块,lerna也支持多模块
    • npm不需要声明dependency依赖,所有模块会被npm install link
    • yarn需要声明模块间的依赖,并且版本要一致,否则会去npm下载依赖包
    • lerna、yarn可以声明依赖的的版本号为* 来总是引用link
  • learn支持版本管理和发布
  • nx支持构建缓存等高级特性

TS Project ReferenceH2

每个模块拥有各自的tsconfig 配置文件,好处是可以自定义path alias等配置。

Monorepo的Path alias

根项目tsconfig

bash

{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"composite": true,
"declaration": true,
"declarationMap": true
},
"files": [],
"references": [{ "path": "packages/root" }, { "path": "packages/system" }]
}

根项目配置的主要目的是引用所有子项目,来触发全局的构建;同时提供公共配置供子项目继承。

重点需要配置compositedeclarationdeclarationMap ,这是必须的。files 对与根项目来说是空,避免和子项目重复引用文件。

子项目tsconfig

bash

{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist/esm",
"rootDir": "./src",
"baseUrl": "./",
"paths": {
"@/*": ["./src/*"],
"@htw-web/*": ["../*/src"]
}
},
"include": ["src"],
"references": [
{ "path": "../root" },
{ "path": "../auth" },
]
}

子项目配置继承父项目配置,下面一些路径相关的配置,需要在每个项目里各自声明。

ViteH2

Vite默认使用esbuild编译typescript文件,不会生成声明文件,可以使用@rollup/plugin-typescript 来生成声明文件

bash

plugins: [
typescript({
tsconfig: resolve(__dirname, 'tsconfig.json'),
exclude: ['__tests__'],
outDir: 'dist/esm',
noEmitOnError: true,
}),
],

编译构建H2

模块间的依赖,需要下面的构建过程正确识别。

  • vscode vscode应该使用的是tsc
  • dev 构建时要保证esbuild能正确加载
  • build 打包时要保证rollup能正确加载;tsc能正确编译

最基本的通过link到node_modules,然后找到package.json 总定义的main指向的文件作为最终的兜底方案肯定是可行的,缺点是必须要先build ,并不是特别适合vscode、dev的场景。

tscH3

tsc通过project reference,加载path alias可以实现。

缺少project reference会提示'rootDir' is expected to contain all source files. ,缺少path alias就只能用相对路径了。

esbuildH3

esbuild可以也会读取tsconfig.json 来解析。

但是还有一个更简化的方案,就说workspace link + package.json#module,module直接指向ts源文件。因为esbuild主要用于dev,还没有build,所以使用main来指向ts文件;而如果使用main,为了确保构建包的正确一般要指向js文件,这就必须要build。

vscodeH3

上述的tsc、esbuild方案任意工作,就可以确保vscode正常工作。tsc的加载方式有限,esbuild相当于兜底方案。

rollupH3

rollup默认只能加载es模块,因此他main执行mjs文件,但是main我们一般指向的是commonjs模式。由于module指向的优先加载,所以可以使用module指向mjs文件。

总结H3

总结来说,ts的方案和npm的方案可以二选一,但是对于最终要发布npm还是要声明package.json中的项目,所以还是推荐npm的方案。

You might not need TypeScript project references

LibraryH2

viteH2

Vite默认使用esbuild编译typescript文件,不会生成声明文件,可以使用@rollup/plugin-typescript 来生成声明文件

bash

plugins: [
typescript({
tsconfig: resolve(__dirname, 'tsconfig.json'),
exclude: ['__tests__'],
outDir: 'dist/esm',
noEmitOnError: true,
}),
],

vite需要配置lib属性来构建library包。ollup最终会emit打包后的文件。推荐的输出目录结构如下

json

"main": "./dist/lib/index.js", // 由rolllup输出
"types": "./dist/esm/index.d.ts", //由tsc输出

如果使用@rollup/plugin-typescript 来输出声明文件,typescript.outDir 必须在 rollupOptions.ouptut.dir 子目录下。 所以esm 不得不变成lib/esm ,因为lib目录还包括其他格式的输出文件,所以包含esm子目录感觉很奇怪。

类型检查H2

由于esbuild等编译工具是不进行类型检查的,得使用TSC进行类型检查。

有Project Rerference引用后,tsc 依赖d.ts文件,不存在则会会报

bash

Output file '/Users/snowblink/Downloads/hithinkway-webapp/packages/root/dist/esm/index.d.ts' has not been built from source file '/Users/snowblink/Downloads/hithinkway-webapp/packages/root/src/index.ts'.

因此必须使用tsc —-build ,否则得先build 生成d.ts文件,所以最后

  • tsc —-build 在跟项目使用
  • tsc 在子项目使用,只关注自己模块的代码问题

使用H1

添加依赖H2

package.json 添加

tsx

dependencies {
"@htw-web/ui": "*"
}

否则会导致

File not include in rootDir

tsconfig.json 添加

tsx

"references": [
{ "path": "../utils" },
]

tsconfigPaths

评论


新的评论

匹配您的Gravatar头像

Joen Yu

@2022 JoenYu, all rights reserved. Made with love.