目录
背景
工具
思考
代码实现
tsconfig.config
package.json
esbuild
babel
rollup
测试
总结
gitee链接
背景
参加公司内部项目开发后的空闲阶段总结一下开发js插件相关的一些东西,相较于直接暴力的将tsx丢到npm仓库的做法这次的总结使得差价开发更为规范化。
工具
esbuildrollupjsbabeltypescriptpackage.json
思考
在日常公司的项目开发中会遇到类似的业务场景并且是在多个不同的项目中,又或者是对于前端团队大,项目多且比较分散,这种情况下要做到不同的项目不同的开发页面样式和风格要统一的情况就需要封装一套公司内部自己的UI框架或针对某个市面上的ui框架(如antd)二次封装来进行统一。
我的上家就是这种情况,在微前端的基础上项目分散成几十个,开发至二期的情况下,业务方当时对我们的页面要求风格进行统一,当时的情况选择了最笨的方法动用了产品/ui/前端前前后后大概有10-15人左右进行为期半个月的统一页面样式的开发这种方式费时费力,如果有一套自己的ui那么这个事情就容易的多。
打包的原则是不将类似react这样的第三方库打进去,直接忽略那么打出来的代码中react会以require('react')这样的形式呈现因为我们实际的项目中已经会安装react这里在编译react的话会造成不必要的包体积。
代码实现
我把三种开发方式都做到同一个项目中了
tsconfig.config
{
"compilerOptions": {
"declaration": true, // 生成相应的d.ts文件
"module": "commonjs", // rollup用ESNext,其他暂时commonjs
"target": "ESNext",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"strict": true,
"allowJs": true,
"jsx": "react",
"rootDirs": ["./node_modules/@type", "src/types.d.ts"],
"esModuleInterop": true, // 允许export=导出,由import from 导入
"emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
"diagnostics": true, // 显示诊断信息。
"declarationDir": "types" // 生成声明文件的输出路径。
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
package.json
定义好main和types(如果是ts包的话),files主要文件夹。当上传npm被下载使用时这些字段会被作为包的入口配置。
{
"name": "babelpackage",
"version": "1.0.0",
"description": "",
"files": [
"lib",
"types"
],
"templateInfo": {
"name": "default",
"typescript": true,
"css": "sass"
},
"main": "lib/index.js",
"types": "./types/index.d.ts",
"scripts": {
"lib": "npm run types && babel --extensions .ts,.tsx --config-file ./babel.config.js --out-dir lib src --copy-files",
"rollup": "npm run types && rollup --config",
"esbuild": "npm run types && node esbuild.config.js",
"types": "tsc"
},
"author": "",
"license": "ISC",
"dependencies": {
"@babel/cli": "^7.18.6",
"@babel/core": "^7.18.6",
"@babel/plugin-transform-runtime": "^7.18.6",
"@babel/preset-env": "^7.18.6",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"esbuild": "^0.14.48",
"esbuild-node-externals": "^1.4.1",
"esbuild-plugin-less": "^1.1.8",
"less": "^4.1.3",
"postcss": "^8.4.14",
"react": "^18.2.0",
"rollup": "^2.75.7",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-typescript2": "^0.32.1",
"typescript": "^4.7.4"
},
"devDependencies": {
"@types/react": "^18.0.15"
}
}
esbuild
esbuild.config.js
esbuild暂不支持css模块,tsx文件中的.less或者.css会被单独打成css文件,在使用的时候需要在手动引入一次css(算是esbuild的一个注意点吧)
const { build } = require("esbuild");
const { lessLoader } = require("esbuild-plugin-less");
const { nodeExternalsPlugin } = require("esbuild-node-externals"); // 不把node_modules的代码打包进来,比自带的external好用
build({
// 单文件
// entryPoints: ["src/esbuild.ts"],
// outfile: "esbuild/out.js",
// 多文件
entryPoints: ["src/esbuild.ts"],
outdir: "esbuild",
bundle: true,
splitting: true,
plugins: [lessLoader(), nodeExternalsPlugin()],
platform: "neutral", // browser, node, neutral(esm)
// external: ["react"], // 外部文件不打包到源码中,esbuild-node-externals更好用
});
babel
babel.config.js
对于babel打包,babel 只负责生成 js 文件,typescript 只负责生成 d.ts 文件,对于 ts 的配置要注意不要生成 js 文件以及定义 d.ts 的输出路径。不能处理css预编译
const presets = [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
]
const plugins = ["@babel/plugin-transform-runtime"]
module.exports = {
presets,
plugins
}
rollup
rollup.config.js
1.rollup打包可以将tsc的功能混入其中。
2.rollup-plugin-typescript2 要单独关联 tsconfig 不然不起作用,同时可以设置默认配置和覆盖配置。
3.如果是开发组件那么要设置参数 modulesOnly: true 不然会直接将类似 react 源码打包出来。
4.没有将 css 打入到 js 文件中需要单独的在引入,切 css 文件都打到同一个 css 文件中
import resolve from "rollup-plugin-node-resolve";
import rollupTypescript from "rollup-plugin-typescript2";
import babel from "rollup-plugin-babel";
import path from "path";
import commonjs from "rollup-plugin-commonjs";
import postcss from "rollup-plugin-postcss";
export default {
input: "src/rollup.ts",
output: {
file: "rollup/index.js",
format: "esm",
},
plugins: [
resolve({
extensions: [".js", ".ts", ".tsx"],
modulesOnly: true, // 只关注模块化(true的时候不会打包react这样的源代码进去)
}),
commonjs(),
postcss({
// extract: true, // true将css抽离出来但是使用的时候要重新引入css,false直接将css打包到js文件中
// extensions: [".css", ".less"],
}),
rollupTypescript({
tsconfig: path.resolve(__dirname, "./tsconfig.json"),
tsconfigOverride: { compilerOptions: { module: "ESNext" } }, // 优先级最高的ts配置
tsconfigDefaults: {}, // 默认ts配置
}),
babel({
exclude: "node_modules/**/*",
runtimeHelpers: true,
extensions: [".js", ".ts", ".tsx"],
}),
],
};
测试
通过在插件工程的根目录下执行npm link,然后在对应要用到插件的项目中执行npm link <插件package.json中的name>,这样就可以起到npm install 的效果了
总结
针对上述三种方式。babel的方式不能预编译css因此要对业务项目进行webpack的工程配置支持编译node_modules的less文件。esbuild速度超快但是js和css打包后会被分开需要单独引入css。rollup会将css打进js文件中如果样式不多的情况下是不错的选择。当然还有涉及到打包后的js模块规范化(umd,commonjs,esm等的)这边后续再做探索。