最终打包效果
这里以
web-loading
插件为例。最初使用Webpack
打包,因为其灵活性和多样化的生态,支持多种加载器和插件。但是,后来发现我的项目并没有涉及到复杂的加载器和插件功能,Webpack
更适用于框架项目。因此,我转向了更为轻便的Rollup
,并使用api-extractor
来合并TS类型定义,使得打包后的插件文件更加紧凑、大小更小。
安装
npm i typescript rollup rollup-plugin-terser @microsoft/api-extractor -Dnpm i typescript rollup rollup-plugin-terser @microsoft/api-extractor -Dnpm i typescript rollup rollup-plugin-terser @microsoft/api-extractor -D
package.json重要配置
{"main": "./dist/web-loading.js", // 指定引入入口"typings": "./dist/web-loading.d.ts", // 指定TypeScript类型入口,提供给Typescript编译器使用"jsdelivr": "./dist/web-loading.js", // 指定了通过 jsdelivr CDN 加载的入口文件路径"unpkg": "./dist/web-loading.js", // 指定了通过 unpkg CDN 加载的入口文件路径"module": "./dist/web-loading.esm-bundler.js", // 指定ES Module引入入口"scripts": {// 首先tsc 打包,rollup抽离,api-extractor run 合并ts类型"build": "tsc && rollup -c rollup.config.js && api-extractor run",},}{ "main": "./dist/web-loading.js", // 指定引入入口 "typings": "./dist/web-loading.d.ts", // 指定TypeScript类型入口,提供给Typescript编译器使用 "jsdelivr": "./dist/web-loading.js", // 指定了通过 jsdelivr CDN 加载的入口文件路径 "unpkg": "./dist/web-loading.js", // 指定了通过 unpkg CDN 加载的入口文件路径 "module": "./dist/web-loading.esm-bundler.js", // 指定ES Module引入入口 "scripts": { // 首先tsc 打包,rollup抽离,api-extractor run 合并ts类型 "build": "tsc && rollup -c rollup.config.js && api-extractor run", }, }{ "main": "./dist/web-loading.js", // 指定引入入口 "typings": "./dist/web-loading.d.ts", // 指定TypeScript类型入口,提供给Typescript编译器使用 "jsdelivr": "./dist/web-loading.js", // 指定了通过 jsdelivr CDN 加载的入口文件路径 "unpkg": "./dist/web-loading.js", // 指定了通过 unpkg CDN 加载的入口文件路径 "module": "./dist/web-loading.esm-bundler.js", // 指定ES Module引入入口 "scripts": { // 首先tsc 打包,rollup抽离,api-extractor run 合并ts类型 "build": "tsc && rollup -c rollup.config.js && api-extractor run", }, }
可以在打包完成之后根据自己的路径填充。
tsc配置文件
tsconfig.json
{"compilerOptions": {"target": "ES5","module": "ESNext","declaration": true,"outDir": "lib"},"include": ["./src/**/*"]}{ "compilerOptions": { "target": "ES5", "module": "ESNext", "declaration": true, "outDir": "lib" }, "include": [ "./src/**/*" ] }{ "compilerOptions": { "target": "ES5", "module": "ESNext", "declaration": true, "outDir": "lib" }, "include": [ "./src/**/*" ] }
这里根据自己业务指定,这里是最终将项目打包成ES模块项目,并最终输出到根目录的lib路径中。
tsc
之后的效果
rollup配置文件
rollup.config.js
import { defineConfig } from 'rollup'import { join } from 'path'import { terser as rollupTerser } from 'rollup-plugin-terser'import rollupJSON from '@rollup/plugin-json'import rollupCommonJS from '@rollup/plugin-commonjs'import rollupReplace from '@rollup/plugin-replace'import rollupNodeResolve from '@rollup/plugin-node-resolve'/*** @typedef {'umd' | 'cjs' | 'esm-bundler'} OutputFormat*//*** @param {OutputFormat} format* @param {boolean} minify* @returns {string}*/function replaceProcessNodeEnv(format, minify) {switch (format) {case 'umd':case 'cjs':return minify ? '"production"' : '"development"'case 'esm-bundler':return 'process.env.NODE_ENV'default:throw new TypeError(`Unsupport format: ${format}`)}}/*** @param {OutputFormat} format* @param {boolean} minify* @returns {string}*/function replaceDev(format, minify) {switch (format) {case 'umd':case 'cjs':return minify ? 'false' : 'true'case 'esm-bundler':return 'process.env.NODE_ENV !== "production"'default:throw new TypeError(`Unsupport format: ${format}`)}}/*** @param {OutputFormat} format* @param {boolean} minify* @returns {import('rollup').RollupOptions}*/function createOption(format, minify) {// 需要指定输出文件前缀const name = `web-loading${format === 'umd' ? '' : `.${format}`}${minify ? '.min' : ''}.js`return {// 入口input: join(__dirname, 'lib/index.js'),plugins: [rollupNodeResolve({mainFields: ['browser', 'module', 'main']}),rollupJSON(),rollupReplace({preventAssignment: true,'process.env.NODE_ENV': replaceProcessNodeEnv(format, minify),__DEV__: replaceDev(format, minify),__VERSION__: JSON.stringify(require('./package.json').version)}),rollupCommonJS({transformMixedEsModules: true,extensions: ['.js', 'jsx', '.ts', '.tsx']}),{name: 'typescript-class-pure',transform(code) {return code.replace(//** @class */ (function/g, '/*#__PURE__*/ (function')}},...(minify? [rollupTerser({output: {comments: false},module: format === 'esm-bundler'})]: [])],output: {// 最终输出文件路径file: join(__dirname, 'dist', name),format: format === 'esm-bundler' ? 'esm' : format,name: 'rustOption',exports: 'named'}}}export default defineConfig([createOption('umd', false),createOption('umd', true),createOption('cjs', false),createOption('cjs', true),createOption('esm-bundler', false)])import { defineConfig } from 'rollup' import { join } from 'path' import { terser as rollupTerser } from 'rollup-plugin-terser' import rollupJSON from '@rollup/plugin-json' import rollupCommonJS from '@rollup/plugin-commonjs' import rollupReplace from '@rollup/plugin-replace' import rollupNodeResolve from '@rollup/plugin-node-resolve' /** * @typedef {'umd' | 'cjs' | 'esm-bundler'} OutputFormat */ /** * @param {OutputFormat} format * @param {boolean} minify * @returns {string} */ function replaceProcessNodeEnv(format, minify) { switch (format) { case 'umd': case 'cjs': return minify ? '"production"' : '"development"' case 'esm-bundler': return 'process.env.NODE_ENV' default: throw new TypeError(`Unsupport format: ${format}`) } } /** * @param {OutputFormat} format * @param {boolean} minify * @returns {string} */ function replaceDev(format, minify) { switch (format) { case 'umd': case 'cjs': return minify ? 'false' : 'true' case 'esm-bundler': return 'process.env.NODE_ENV !== "production"' default: throw new TypeError(`Unsupport format: ${format}`) } } /** * @param {OutputFormat} format * @param {boolean} minify * @returns {import('rollup').RollupOptions} */ function createOption(format, minify) { // 需要指定输出文件前缀 const name = `web-loading${format === 'umd' ? '' : `.${format}`}${minify ? '.min' : ''}.js` return { // 入口 input: join(__dirname, 'lib/index.js'), plugins: [ rollupNodeResolve({ mainFields: ['browser', 'module', 'main'] }), rollupJSON(), rollupReplace({ preventAssignment: true, 'process.env.NODE_ENV': replaceProcessNodeEnv(format, minify), __DEV__: replaceDev(format, minify), __VERSION__: JSON.stringify(require('./package.json').version) }), rollupCommonJS({ transformMixedEsModules: true, extensions: ['.js', 'jsx', '.ts', '.tsx'] }), { name: 'typescript-class-pure', transform(code) { return code.replace(//** @class */ (function/g, '/*#__PURE__*/ (function') } }, ...(minify ? [ rollupTerser({ output: { comments: false }, module: format === 'esm-bundler' }) ] : []) ], output: { // 最终输出文件路径 file: join(__dirname, 'dist', name), format: format === 'esm-bundler' ? 'esm' : format, name: 'rustOption', exports: 'named' } } } export default defineConfig([ createOption('umd', false), createOption('umd', true), createOption('cjs', false), createOption('cjs', true), createOption('esm-bundler', false) ])import { defineConfig } from 'rollup' import { join } from 'path' import { terser as rollupTerser } from 'rollup-plugin-terser' import rollupJSON from '@rollup/plugin-json' import rollupCommonJS from '@rollup/plugin-commonjs' import rollupReplace from '@rollup/plugin-replace' import rollupNodeResolve from '@rollup/plugin-node-resolve' /** * @typedef {'umd' | 'cjs' | 'esm-bundler'} OutputFormat */ /** * @param {OutputFormat} format * @param {boolean} minify * @returns {string} */ function replaceProcessNodeEnv(format, minify) { switch (format) { case 'umd': case 'cjs': return minify ? '"production"' : '"development"' case 'esm-bundler': return 'process.env.NODE_ENV' default: throw new TypeError(`Unsupport format: ${format}`) } } /** * @param {OutputFormat} format * @param {boolean} minify * @returns {string} */ function replaceDev(format, minify) { switch (format) { case 'umd': case 'cjs': return minify ? 'false' : 'true' case 'esm-bundler': return 'process.env.NODE_ENV !== "production"' default: throw new TypeError(`Unsupport format: ${format}`) } } /** * @param {OutputFormat} format * @param {boolean} minify * @returns {import('rollup').RollupOptions} */ function createOption(format, minify) { // 需要指定输出文件前缀 const name = `web-loading${format === 'umd' ? '' : `.${format}`}${minify ? '.min' : ''}.js` return { // 入口 input: join(__dirname, 'lib/index.js'), plugins: [ rollupNodeResolve({ mainFields: ['browser', 'module', 'main'] }), rollupJSON(), rollupReplace({ preventAssignment: true, 'process.env.NODE_ENV': replaceProcessNodeEnv(format, minify), __DEV__: replaceDev(format, minify), __VERSION__: JSON.stringify(require('./package.json').version) }), rollupCommonJS({ transformMixedEsModules: true, extensions: ['.js', 'jsx', '.ts', '.tsx'] }), { name: 'typescript-class-pure', transform(code) { return code.replace(//** @class */ (function/g, '/*#__PURE__*/ (function') } }, ...(minify ? [ rollupTerser({ output: { comments: false }, module: format === 'esm-bundler' }) ] : []) ], output: { // 最终输出文件路径 file: join(__dirname, 'dist', name), format: format === 'esm-bundler' ? 'esm' : format, name: 'rustOption', exports: 'named' } } } export default defineConfig([ createOption('umd', false), createOption('umd', true), createOption('cjs', false), createOption('cjs', true), createOption('esm-bundler', false) ])
这里可以把它当作固定写法,也可以自定义,但
createOption
函数中输出可以自定义文件前缀。
rollup -c rollup.config.js
之后的效果
此时已经将
lib
中的js
文件抽离,并打包了输出dist
路径中。
api-extractor配置文件
api-extractor.json
{"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json","mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts","bundledPackages": [],"compiler": {"tsconfigFilePath": "<projectFolder>/tsconfig.json"},"apiReport": {"enabled": false},"docModel": {"enabled": true},"dtsRollup": {"enabled": true,// 合并类型后的文件名"untrimmedFilePath": "<projectFolder>/dist/web-loading.d.ts"},"tsdocMetadata": {"enabled": true,"tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"},"messages": {"compilerMessageReporting": {"default": {"logLevel": "warning"}},"extractorMessageReporting": {"default": {"logLevel": "warning"},"ae-forgotten-export": {"logLevel": "none"}},"tsdocMessageReporting": {"default": {"logLevel": "warning"}}}}{ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", "mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts", "bundledPackages": [], "compiler": { "tsconfigFilePath": "<projectFolder>/tsconfig.json" }, "apiReport": { "enabled": false }, "docModel": { "enabled": true }, "dtsRollup": { "enabled": true, // 合并类型后的文件名 "untrimmedFilePath": "<projectFolder>/dist/web-loading.d.ts" }, "tsdocMetadata": { "enabled": true, "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json" }, "messages": { "compilerMessageReporting": { "default": { "logLevel": "warning" } }, "extractorMessageReporting": { "default": { "logLevel": "warning" }, "ae-forgotten-export": { "logLevel": "none" } }, "tsdocMessageReporting": { "default": { "logLevel": "warning" } } } } { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", "mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts", "bundledPackages": [], "compiler": { "tsconfigFilePath": "<projectFolder>/tsconfig.json" }, "apiReport": { "enabled": false }, "docModel": { "enabled": true }, "dtsRollup": { "enabled": true, // 合并类型后的文件名 "untrimmedFilePath": "<projectFolder>/dist/web-loading.d.ts" }, "tsdocMetadata": { "enabled": true, "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json" }, "messages": { "compilerMessageReporting": { "default": { "logLevel": "warning" } }, "extractorMessageReporting": { "default": { "logLevel": "warning" }, "ae-forgotten-export": { "logLevel": "none" } }, "tsdocMessageReporting": { "default": { "logLevel": "warning" } } } }
注意
untrimmedFilePath
最后输出的类型文件名。
api-extractor run
之后的效果
可以看到项目中新增了合并后的类型文件,最后根据package.json配置入口即可。
npm上传配置
为了上传npm插件包时减小文件体积,可以新增一个名为.npmignore
的配置文件,并在其中列出不需要被上传到npm注册表中的文件或目录。这样,在运行npm publish
后,只会将定义在package.json
中的files
字段以及符合.npmignore
设置的文件列表一并打包发布,自己的源码就不会被上传到npm仓库,从而使npm插件包的文件大小更小。
srctemplib.eslint*docsapi-extractor.jsonrollup.config*tsconfig*package-lock.jsonsrc temp lib .eslint* docs api-extractor.json rollup.config* tsconfig* package-lock.jsonsrc temp lib .eslint* docs api-extractor.json rollup.config* tsconfig* package-lock.json
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END