您现在的位置是:网站首页> 编程资料编程资料

使用typescript+webpack构建一个js库的示例详解_javascript技巧_

2023-05-24 218人已围观

简介 使用typescript+webpack构建一个js库的示例详解_javascript技巧_

记录使用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中,我们配置了两个入口分别是indexindex.min,不难看出,多出的一个index.min入口是为了经过压缩后js和css文件,在生产环境使用一般都会使用.min.js结尾的文件以减少网络传输时的尺寸; 实现这个还需要结合optimization相关配置, 如下:

optimization: { minimize: true, minimizer: [ new TerserPlugin({ test: /.min.js$/ }), new CssMinimizer({ test: /.min.css$/, }), ], },

另外,indexindex.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目录中, umdUniversal Module Definition(通用模块定义)的缩写, umd格式输出library允许用户通过commonjs, AMD,