UNPKG

@autopack/cpack

Version:

📦 基于rollup的JS、TS包构建工具 | One common construction and package tool for JS/TS components based on Rollup 📦

381 lines (363 loc) 11.4 kB
/** * rollup 配置生成器 */ const path = require('path') const toString = require('lodash/toString') const peerDepsExternal = require('rollup-plugin-peer-deps-external') const resolve = require('@rollup/plugin-node-resolve').nodeResolve const commonjs = require('@rollup/plugin-commonjs') const json = require('@rollup/plugin-json') // const url = require('rollup-plugin-url') // const livereload = require('rollup-plugin-livereload') const alias = require('@rollup/plugin-alias') const postcss = require('rollup-plugin-postcss') const typescript = require('rollup-plugin-typescript2') const presetEnv = require('@babel/preset-env') const babel = require('@rollup/plugin-babel').babel const proposalDecoratorsPlugins = require('@babel/plugin-proposal-decorators') const proposalClassPlugins = require('@babel/plugin-proposal-class-properties') const runtimePlugins = require('@babel/plugin-transform-runtime') const replace = require('@rollup/plugin-replace') const autoprefixer = require('autoprefixer') // const syntaxDynamicImportPlugins = require('@babel/plugin-syntax-dynamic-import'); const filesize = require('rollup-plugin-filesize') const getFiles = require('../loader/files-loader') // const html = require('@rollup/plugin-html') // const fs = require('fs') const { extensions, excludeExtensions } = require('../common') // UMD/IIFE shared settings: output.globals // Refer to https://rollupjs.org/guide/en#output-globals for details const globals = { // Provide global variable names to replace your external imports jquery: '$' } const tempProperty = [ 'skipAlert', 'formatConfig', 'templateBase', 'devServeInput', 'batchPackage', 'stylusAlias', 'replaceMaps', 'styleExtract' ] // const EXTERNAL = [Object.keys(pkg.devDependencies)].concat(Object.keys(pkg.peerDependencies)) const isProd = require('../utils/index').isProd() const cssModulesConfig = isProd ? { generateScopedName: '[hash:base64:5]' } : true module.exports = (packConfig, pkg, formatMapping, cliConfig) => { const version = process.env.VERSION || pkg.version const { sourceFormat } = cliConfig const stylusAlias = packConfig.stylusAlias const replaceMaps = packConfig.replaceMaps || {} const Evaluator = require('stylus').Evaluator if (stylusAlias) { const visitImport = Evaluator.prototype.visitImport Evaluator.prototype.visitImport = function (imported) { const path = imported.path.first if (path.string.startsWith('~')) { const alias = Object.keys(stylusAlias).find((entry) => path.string.startsWith(`~${entry}`) ) if (alias) { path.string = path.string.substr(1).replace(alias, stylusAlias[alias]) } } return visitImport.call(this, imported) } } const baseConfig = { ...packConfig, plugins: [] } const basePlugins = { preBase: [ json(), // url({ limit: 10 * 1024 }), replace({ preventAssignment: true, __VERSION__: version, __ENV__: JSON.stringify('production'), ...replaceMaps }) ], preConfig: [ alias({ entries: [ { find: '@', replacement: path.resolve(process.cwd(), './src') }, { find: '-', replacement: path.join(__dirname, '../../node_modules') } ] }), // stylus(), postcss({ extensions: ['.css', '.styl', '.sass', '.scss'], modules: cssModulesConfig, plugins: [autoprefixer()], sourceMap: false, extract: packConfig?.styleExtract ? `${packConfig.output.directory}/style/style.css` : false, minimize: true, inject: true }) // css(), ], babel: { exclude: ['node_modules/**', 'autopack.config.js'], extensions, babelHelpers: 'bundled', plugins: [ // syntaxDynamicImportPlugins, [proposalDecoratorsPlugins, { legacy: true }], [proposalClassPlugins, { loose: true }] // runtimePlugins, ] }, babelPreset: [ presetEnv, { targets: { browsers: [ 'last 3 versions', '> 2%', 'ie >= 9', 'Firefox >= 30', 'Chrome >= 30' ] }, modules: false, loose: true, shippedProposals: true } ], tsConfig: { check: false, // tsconfig: path.resolve(__dirname, '../../tsconfig.json'), tsconfigOverride: { compilerOptions: { declarationDir: path.resolve( process.cwd(), `./${packConfig.output.directory}/types` ) } }, useTsconfigDeclarationDir: true, // emitDeclarationOnly: true, typescript: require('typescript') }, postBase: [ filesize(), process.env.NODE_ENV !== 'production' && cliConfig.debug && require('rollup-plugin-serve')({ open: true, // 是否打开浏览器 contentBase: [ path.resolve(process.cwd(), packConfig.templateBase ?? ''), // 入口html文件位置 path.resolve(process.cwd(), packConfig.output?.directory ?? '') // 入口dist文件位置 ], historyApiFallback: true, // return index.html instead of 404 host: 'localhost', port: 3003, // // set headers // headers: { // 'Access-Control-Allow-Origin': '*' // }, // // execute function after server has begun listening onListening: function (server) { const address = server.address() const host = address.address === '::' ? 'localhost' : address.address // by using a bound function, we can access options as `this` const protocol = this.https ? 'https' : 'http' console.log( `Server listening at ${protocol}://${host}:${address.port}/` ) }, verbose: true // 打印输出serve路径 }) // process.env.NODE_ENV !== 'production' && // cliConfig.debug && // require('@rollup/plugin-html')({ // dest: 'example', // filename: 'index.html', // template: () => fs.readFileSync(path.resolve( // process.cwd(), // './example/template.html' // )), // ignore: /cjs\.js/ // }) // livereload({ // watch: packConfig.output.directory, // port: 35729 // } ], postConfig: [ resolve({ extensions, mainFields: ['jsnext:main', 'preferBuiltins', 'browser'] }), commonjs() ] } const commonJSConf = (esMod = true) => [ ...basePlugins.preConfig, babel({ exclude: ['node_modules/**', 'autopack.config.js'], extensions: ['.mjs', ...extensions], babelHelpers: 'runtime', // babelrc: false, presets: [ basePlugins.babelPreset // ["@babel/preset-typescript"] ], plugins: [ // syntaxDynamicImportPlugins, [proposalDecoratorsPlugins, { legacy: true }], [proposalClassPlugins, { loose: true }], [runtimePlugins, { useESModules: esMod }] ] }), ...basePlugins.postConfig ] const commonTSConf = [ ...basePlugins.preConfig, ...basePlugins.postConfig, typescript(basePlugins.tsConfig) ] function mapFormatToConfig (format, sourceFormat) { // esm格式配置 if (format === 'es') { const esPluginMap = { js: commonJSConf(true), ts: commonTSConf } const esPlugins = esPluginMap[sourceFormat] || [] const esConfig = { ...baseConfig, plugins: [ peerDepsExternal(), ...basePlugins.preBase, ...esPlugins, ...basePlugins.postBase ] } return esConfig } // commonjs格式配置 if (format === 'cjs') { const cjsPluginMap = { js: commonJSConf(false), ts: commonTSConf } const cjsPlugins = cjsPluginMap[sourceFormat] || [] const cjsConfig = { ...baseConfig, plugins: [ peerDepsExternal(), ...basePlugins.preBase, ...cjsPlugins, ...basePlugins.postBase ] } return cjsConfig } // umd格式配置 if (format === 'umd') { const umdPluginMap = { js: commonJSConf(false), ts: commonTSConf } const umdPlugins = umdPluginMap[sourceFormat] || [] const umdConfig = { ...baseConfig, plugins: [ ...basePlugins.preBase, ...umdPlugins, ...basePlugins.postBase ] } return umdConfig } // iife和amd格式配置 if (format === 'iife' || format === 'amd') { const unpkgPluginsMap = { js: [ ...basePlugins.preConfig, babel({ ...basePlugins.babel, presets: [basePlugins.babelPreset], plugins: [ // syntaxDynamicImportPlugins, [proposalDecoratorsPlugins, { legacy: true }], [proposalClassPlugins, { loose: true }] ] }), ...basePlugins.postConfig ], ts: commonTSConf } const unpkgPlugins = unpkgPluginsMap[sourceFormat] || [] const unpkgConfig = { ...baseConfig, plugins: [ ...basePlugins.preBase, ...unpkgPlugins, ...basePlugins.postBase ] } return unpkgConfig } } const pkgDeps = pkg.dependencies ? Object.keys(pkg.dependencies).map((d) => toString(d)) : [] const rollupConfigRes = packConfig.output.format.reduce((acc, format) => { const { external = [], isolateDep } = packConfig.formatConfig?.[format] ?? {} const externals = isolateDep ? pkgDeps.concat(external) : external const configRes = mapFormatToConfig(format, sourceFormat) const config = { ...configRes, output: { ...packConfig.output, file: `${packConfig.output.directory}/${packConfig.output.name}${ formatMapping[format] ? `${formatMapping[format]}` : '' }`, format, sourcemap: isProd, compact: format !== 'es', exports: format === 'es' ? 'named' : 'auto', globals }, external: [...new Set(externals)] } // 非prod环境并且是debug状态并且devServeInput有值时,切换input为指定example入口文件 if (!isProd && !!cliConfig.debug && !!packConfig.devServeInput) { config.input = packConfig.devServeInput ?? '' } // batchPackage为true时,会自动开启批量打包, 默认批量路径为"./packages",可配置 input 数组属性指定input路径文件 if (!!packConfig?.batchPackage) { config.input = [ ...getFiles('./packages', extensions, excludeExtensions) ] } tempProperty.forEach((property) => { if (Object.prototype.hasOwnProperty.call(config, property)) { delete config[property] } if (Object.prototype.hasOwnProperty.call(config.output, 'directory')) { delete config.output.directory } }) return [...acc, config] }, []) return rollupConfigRes }