这篇文章主要介绍了typescript+webpack构建一个js库,本文主要记录使用typescript配合webpack打包一个javascript library的配置过程,需要的朋友可以参考下
记录使用typescript配合webpack打包一个javascript library的配置过程.
目标是构建一个可以同时支持CommonJs
, esm
, amd
这个几个js模块系统的javascript库, 然后还有一个单独打包出一个css的样式文件的需求.
为此以构建一个名为loaf
的javascript库为例; 首先新建项目文件目录loaf
, 并进入此文件目录执行npm init
命令, 然后按照控制台的提示输入对应的信息, 完成后就会在loaf目录下得到一个package.json
文件
然后使用npm i
命令安装所需的依赖
npm i -D webpack webpack-cli typescript babel-loader @babel/core @babel/preset-env @babel/preset-typescript ts-node @types/node @types/webpack mini-css-extract-plugin css-minimizer-webpack-plugin less less-loader terser-webpack-plugin
依赖说明
- webpack webpack-cli: webpack打包工具和webpack命令行接口
- typescript: 用于支持typescript语言
- babel-loader @babel/core @babel/preset-env @babel/preset-typescript: babel相关的东西, 主要是需要babel-loader将编写的typescript代码转译成es5或es6已获得更好的浏览器兼容性
- ts-node @types/node @types/webpack: 安装这几个包是为了能用typescript编写webpack配置文件(webpack.config.ts)
- mini-css-extract-plugin less less-loader: 编译提取less文件到单独的css文件的相关依赖
- css-minimizer-webpack-plugin terser-webpack-plugin: 用于最小化js和css文件尺寸的webpack插件
入口文件
通常使用index.ts
作为入口, 并将其放到src
目录下, 由于有输出样式文件的需求, 所以还要新建styles/index.less
mkdir src && touch src/index.ts mkdir src/styles && touch src/styles/index.less
tsconfig配置
新建tsconfig.json
文件
touch tsconfig.json
填入以下配置(部分选项配有注释):
{ "compilerOptions": { "outDir": "dist/lib", "sourceMap": false, "noImplicitAny": true, "module": "commonjs", // 开启这个选项, 可以让你直接通过`import`的方式来引用commonjs模块 // 这样你的代码库中就可以统一的使用import导入依赖了, 而不需要另外再使用require导入commonjs模块 "esModuleInterop": true, // 是否允许合成默认导入 // 开启后, 依赖的模块如果没有导出默认的模块 // 那么typescript会帮你给该模块自动合成一个默认导出让你可以通过默认导入的方式引用该模块 "allowSyntheticDefaultImports": true, // 是否生成`.d.ts`的类型声明文件 "declaration": true, // 输出的目标js版本, 这里用es6, 然后配和babel进行转译才以获得良好的浏览器兼容 "target": "es6", "allowJs": true, "moduleResolution": "node", "lib": ["es2015", "dom"], "declarationMap": true, // 启用严格的null检查 "strictNullChecks": true, // 启用严格的属性初始化检查 // 启用后类属性必须显示标注为可空或赋一个非空的初始值 "strictPropertyInitialization": true }, "exclude": ["node_modules"], "include": ["src/**/*"] }
webpack配置文件
创建webpack.config.ts
touch webpack.config.ts
webpack.config.ts
import path from "path"; import { Configuration, Entry } from "webpack"; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import CssMinimizer from 'css-minimizer-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin' const isProd = process.env.NODE_ENV === 'production'; /** * 这里用到了webpack的[Multiple file types per entry](https://webpack.js.org/guides/entry-advanced/)特性 * 注意`.less`入口文件必须放在`.ts`文件前 */ const entryFiles: string[] = ['./src/styles/index.less', './src/index.ts']; const entry: Entry = { index: entryFiles, 'index.min': entryFiles, }; const config: Configuration = { entry, optimization: { minimize: true, minimizer: [ new TerserPlugin({ test: /.min.js$/ }), new CssMinimizer({ test: /.min.css$/, }), ], }, module: { rules: [ { test: /.ts$/, loader: 'babel-loader', exclude: /node_modules/, options: { presets: ['@babel/env', '@babel/typescript'], }, }, { test: /.less$/, use: [ isProd ? MiniCssExtractPlugin.loader : 'style-loader', { loader: 'css-loader', }, 'postcss-loader', 'less-loader', ], }, ], }, output: { path: path.resolve(__dirname, 'dist/umd'), library: { type: 'umd', name: { amd: 'loaf', commonjs: 'loaf', root: 'loaf', }, }, }, resolve: { extensions: ['.ts', '.less'], }, devtool: 'source-map', plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', }), ], }; export default config;
webpack入口文件配置
... const isProd = process.env.NODE_ENV === 'production'; /** * 这里用到了webpack的[Multiple file types per entry](https://webpack.js.org/guides/entry-advanced/)特性 * 注意`.less`入口文件必须放在`.ts`文件前 */ const entryFiles: string[] = ['./src/styles/index.less', './src/index.ts']; const entry: Entry = { index: entryFiles, 'index.min': entryFiles, }; const config: Configuration = { entry, ... } ...
在上面的webpack.config.json
中,我们配置了两个入口分别是index
和index.min
,不难看出,多出的一个index.min
入口是为了经过压缩后js和css文件,在生产环境使用一般都会使用.min.js
结尾的文件以减少网络传输时的尺寸; 实现这个还需要结合optimization
相关配置, 如下:
optimization: { minimize: true, minimizer: [ new TerserPlugin({ test: /.min.js$/ }), new CssMinimizer({ test: /.min.css$/, }), ], },
另外,index
和index.min
的值都是相同的entryFiles
对象,这个对象是一个字符串数组,里面放的就是我们的入口文件相对路径,这里一定要注意把./src/styles/index.less
置于./src/index.ts
之前。
webpack为typescript和less文件配置各自的loader
配置完入口后, 就需要为typescript和less代码配置各自的loader
module: { rules: [ { test: /.ts$/, loader: 'babel-loader', exclude: /node_modules/, options: { presets: ['@babel/env', '@babel/typescript'], }, }, { test: /.less$/, use: [ isProd ? MiniCssExtractPlugin.loader : 'style-loader', { loader: 'css-loader', }, 'postcss-loader', 'less-loader', ], }, ], },
mini-css-extract-plugin less less-loader
: 编译提取less文件到单独的css文件的相关依赖
上面的配置为.ts结尾的文件配置了babel-loader; 为.less
结尾的文件配置一串loader, 使用了use
, use中的loader的执行顺序是从后往前的, 上面less的配置就是告诉webpack遇到less文件时, 一次用less-loader
->postcss-loader
->css-loader
->生产环境用 MiniCssExtractPlugin.loader() 否则用 style-loader
;
MiniCssExtractPlugin.loader
使用前要先在plugins
进行初始化
... const config = { ... plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', }), ], ... } ...
webpack的output配置
... const config = { ... output: { path: path.resolve(__dirname, 'dist/umd'), library: { type: 'umd', name: { amd: 'loaf', commonjs: 'loaf', root: 'loaf', }, }, }, ... } ...
这里配置webpack以umd的方式输出到相对目录dist/umd
目录中, umd
是Universal Module Definition
(通用模块定义)的缩写, umd格式输出library允许用户通过commonjs
, AMD
,