runTask('buildFullBundle')

打包出来的结构

我们对应里面有两个并行运行的任务,里面的 minify 就是是否要将打包出来代码进行压缩混淆
scss
export const buildFull = (minify: boolean) => async () =>
Promise.all([buildFullEntry(minify), buildFullLocale(minify)])
export const buildFullBundle: TaskFunction = parallel(
withTaskName('buildFullMinified', buildFull(true)),
withTaskName('buildFull', buildFull(false))
)
buildFullEntry
php
async function buildFullEntry(minify: boolean) {
const plugins: Plugin[] = [
ElementPlusAlias(),
VueMacros({
setupComponent: false,
setupSFC: false,
plugins: {
vue: vue({
isProduction: true,
template: {
compilerOptions: {
hoistStatic: false,
cacheHandlers: false,
},
},
}),
vueJsx: vueJsx(),
},
}),
nodeResolve({
extensions: ['.mjs', '.js', '.json', '.ts'],
}),
commonjs(),
esbuild({
exclude: [],
sourceMap: minify,
target,
loaders: {
'.vue': 'ts',
},
define: {
'process.env.NODE_ENV': JSON.stringify('production'),
},
treeShaking: true,
legalComments: 'eof',
}),
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
]
if (minify) {
plugins.push(
minifyPlugin({
target,
sourceMap: true,
})
)
}
const bundle = await rollup({
input: path.resolve(epRoot, 'index.ts'),
plugins,
external: await generateExternal({ full: true }),
treeshake: true,
})
await writeBundles(bundle, [
{
format: 'umd',
file: path.resolve(
epOutput,
'dist',
formatBundleFilename('index.full', minify, 'js')
),
exports: 'named',
name: PKG_CAMELCASE_NAME,
globals: {
vue: 'Vue',
},
sourcemap: minify,
banner,
},
{
format: 'esm',
file: path.resolve(
epOutput,
'dist',
formatBundleFilename('index.full', minify, 'mjs')
),
sourcemap: minify,
banner,
},
])
}
我们来看对应的代码挨个说明
ElementPlusAlias
:见上一小结VueMacros
:见上一小节nodeResolve
:见上一小节commonjs
:见上一小节esbuild
- sourceMap值为minify,也就是说,如果不压缩就不需要sourceMap,因为打包出来的代码是比较好识别的,因为代码没有进行压缩混淆
- define:这里作用和
@rollup/plugin-replace
插件作用一样,就是将对应代码进行字符替换。如果注释掉对应的代码,打包的结果中就会出现下面的代码process.env.NODE_ENV
。并且替换了之后可以借助treeShaking处理掉为false的代码 - treeShaking:去除掉不会运行的代码
- legalComments:JavaScript 中,有些注释具有特殊的法律意义或功能。这个可以防止对应的注释打包被消除
- sourceMap值为minify,也就是说,如果不压缩就不需要sourceMap,因为打包出来的代码是比较好识别的,因为代码没有进行压缩混淆
replace
:@rollup/plugin-replace
插件,和上面的define配置效果一样- 如果有minify是true,需要加入
rollup-plugin-esbuild
中的minify
插件,并且sourceMap需要为true(对应就是例如index.full.min.js.map
)
我们思考一下全量打包需要替换 process.env.NODE_ENV
为字符串"production"
的原因,为啥上一期我们打包模块不需要:因为全量打包是相当于直接生产使用的,所以必须去掉对应的process.env.NODE_ENV
,而我们上一期的打包内容是给构建工具使用的,构建工具打包的时候才会去自行处理。例如vite的NODE_ENV如下图,可见官网
然后我们来看这块代码
php
const bundle = await rollup({
input: path.resolve(epRoot, 'index.ts'),
plugins,
external: await generateExternal({ full: true }),
treeshake: true,
})
入口文件就是packages/element-plus/index.ts
;plugins就是上面说的各个插件配置;external这个generateExternal中full为true时候就只会排除vue的相关依赖。
我们主要来说下treeshake这个配置,这里的配置是true是rollup的标准树摇模式。
对于treeshake: { moduleSideEffects: false }
假定了所有模块都是没有副作用的。可以配合package.json中的sideEffects
配置手动设置哪些文件是有副作用的,避免被误删除。例如packages\components\package.json
中有配置 。
treeshake: { moduleSideEffects: false }
很高效,并且可以使得打包体积更小,风险就是可能会被错误的扔掉有副作用代码。所以和sideEffects
配合使用。
继续看下writeBundles
:
php
await writeBundles(bundle, [
{
format: 'umd',
file: path.resolve(
epOutput,
'dist',
formatBundleFilename('index.full', minify, 'js')
),
exports: 'named',
name: PKG_CAMELCASE_NAME,
globals: {
vue: 'Vue',
},
sourcemap: minify,
banner,
},
{
format: 'esm',
file: path.resolve(
epOutput,
'dist',
formatBundleFilename('index.full', minify, 'mjs')
),
sourcemap: minify,
banner,
},
])
这里两个版本:
- umd:生成一个兼容性最强的版本
- 可以
<script>
标签直接引入,通过name: PKG_CAMELCASE_NAME
就可以定义全局变量挂载在window上。也可以CommonJS的require()使用 globals
: 指定了外部依赖(externals
)如何被处理。这里告诉 Rollup:import vue from 'vue'
语句中的'vue'
这个模块,对应的是全局变量Vue
- 可以
- esm格式,通过import引入,所以没有
name
和globals
对于file、exports、sourceMap和前面讲解的作用一样不多赘述。
对于banner,就是文件头部添加的注释(如版权信息),如下图
buildFullLocale
less
async function buildFullLocale(minify: boolean) {
const files = await glob(`**/*.ts`, {
cwd: path.resolve(localeRoot, 'lang'),
absolute: true,
})
return Promise.all(
files.map(async (file) => {
const filename = path.basename(file, '.ts')
const name = upperFirst(camelCase(filename))
const bundle = await rollup({
input: file,
plugins: [
esbuild({
minify,
sourceMap: minify,
target,
}),
],
})
await writeBundles(bundle, [
{
format: 'umd',
file: path.resolve(
epOutput,
'dist/locale',
formatBundleFilename(filename, minify, 'js')
),
exports: 'default',
name: `${PKG_CAMELCASE_LOCAL_NAME}${name}`,
sourcemap: minify,
banner,
},
{
format: 'esm',
file: path.resolve(
epOutput,
'dist/locale',
formatBundleFilename(filename, minify, 'mjs')
),
sourcemap: minify,
banner,
},
])
})
)
}
对于语言包,我们打包入口是packages\locale\lang
中的每个ts文件。不是packages\locale\index.ts
,因为需要方便按需引入。如果从index.ts引入的话就会全部语言都打包成一个。
其他的参数都类似。exports这里参数是default,适用于只使用 export default ...
的情况,可见文档