element-plus源码分析-构建流程之full-bundle

2023/11/29 element-plus

阅读这篇文章前,请先了解 element-plus源码分析-构建流程

full-bundle 是打包给浏览器的环境使用的,入口为 packages/element-plus/index.ts,出口为 dist/element-plus/dist/index.full(.min).(mjs|js)

async function buildFullEntry(minify: boolean) {
  const bundle = await rollup({
    input: path.resolve(epRoot, 'index.ts'),
    plugins: [
      ElementPlusAlias(),
      vue({
        isProduction: true
      }),
      nodeResolve({
        extensions: ['.mjs', '.js', '.json', '.ts'],
      }),
      commonjs(),
      esbuild({
        minify,
        sourceMap: minify,
        target,
      }),
      replace({
        'process.env.NODE_ENV': JSON.stringify('production'),

        // options
        preventAssignment: true,
      }),
      filesize(),
    ],
    external: await generateExternal({ full: true }),
  })
  await writeBundles(bundle, [
    {
      format: 'umd',
      file: path.resolve(
        epOutput,
        'dist',
        formatBundleFilename('index.full', minify, 'js')
      ),
      exports: 'named',
      name: 'ElementPlus',
      globals: {
        vue: 'Vue',
      },
      sourcemap: minify,
      banner,
    },
    {
      format: 'esm',
      file: path.resolve(
        epOutput,
        'dist',
        formatBundleFilename('index.full', minify, 'mjs')
      ),
      sourcemap: minify,
      banner,
    },
  ])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

来看看 ElementPlusAlias 插件做了什么事情:

import { EP_PKG, EP_PREFIX } from '../utils/constants'
import type { Plugin } from 'rollup'

export function ElementPlusAlias(): Plugin {
  const THEME_CHALK = `${EP_PREFIX}/theme-chalk`

  return {
    name: 'element-plus-alias-plugin',
    resolveId(id, importer, options) {
      if (!id.startsWith(EP_PREFIX)) return

      if (id.startsWith(THEME_CHALK)) {
        return {
          id: id.replaceAll(THEME_CHALK, `${EP_PKG}/theme-chalk`),
          external: 'absolute',
        }
      }

      return this.resolve(id, importer, { skipSelf: true, ...options })
    },
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

这里处理 [resolveId](https://www.rollupjs.com/guide/plugin-development#resolveid) 钩子,rollup 中模块(文件)的id就是文件地址,所以类似resolveID这种就是解析文件地址的意思,我们可以返回我们想返回的文件id(也就是地址,相对路径、决定路径)来让rollup加载。EP_PREFIX的值是 @element-plus , EP_PKG的值是 element-plus ,也就是不是 @element-plus的模块不打包,并且遇到的模块 @element-plus/theme-chalk 名称改为 element-plus/theme-chalk。也就是将js中的 样式文件的路径改为实际打包后的文件引用地址。(不过貌似 element-plus 源码中找不到那个 @element-plus/theme-chalk路径)

然后是 import vue from '@vitejs/plugin-vue'这个是导入 vite 的 vue 插件,真是烦单从这两行代码只能猜是用于 vite 解析 vue 文件的,而文档几乎啥也没写(需要的话只能去看源码了),就直接这样用吧前端真是乱,工程实践很多都是这样。

nodeResolve 这个 rollup-plugin-node-resolve (opens new window) 插件可以告诉 Rollup 如何查找外部模块。

目前, npm 中的大多数包都是以 CommonJS 模块的形式出现的。在它们更改之前,我们需要将 CommonJS 模块转换为 ES2015 供 Rollup 处理。这个 rollup-plugin-commonjs (opens new window) 插件就是用来将 CommonJS 转换成 ES2015 模块的。

esbuild 是将 TS/ESNext 编译成 ES6.

@rollup/plugin-replace是在打包的过程中将目标字符串替换。

rollup-plugin-filesize 是用来显示打包后的文件大小的插件。

来看 rollup 不打包进的依赖包:


export const generateExternal = async (options: { full: boolean }) => {
  const { dependencies, peerDependencies } = await getPackageDependencies(
    epPackage
  )

  return (id: string) => {
    const packages: string[] = peerDependencies
    if (!options.full) {
      packages.push('element-plus/theme-chalk')
      // dependencies
      packages.push('@vue', ...dependencies)
    }

    return [...new Set(packages)].some(
      (pkg) => id === pkg || id.startsWith(`${pkg}/`)
    )
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

上面的意思是:将epPackage对应的package.json的上某些相关依赖不打包。

行了,你开始打包吧。

更新时间: 2023/11/29 15:42:16