优化 rollup 配置以启用 tree shaking
optimize rollup config to enable tree shaking
我想就如何构建一个易于使用和 tree-shaking 优化的构建提出建议。我正在使用 rollup 打包一个由多个组件组成的 UI 库。
我的架构是:
/src
/index.js
/components
/index.js
/component1
/index.js
/Comp.vue
...
/componentN
/index.js
/Comp.vue
/directives
/index.js
/directive1
/index.js
...
/directiveN
/index.js
src/components/index.js
看起来像
export { default as Comp1 } from './component1
...
export { default as CompN } from './componentN
src/directives/index.js
看起来像
export { default as Directive1 } from './directive1
...
export { default as DirectiveN } from './directiveN
每个内部index.js
只是为了方便而绑定,比如
import Comp from './Comp.vue'
export default Comp`
最后 src/index.js
将收集所有内容:
import { * as components } from './components'
import { * as directives } from './directives'
export { components, directives }
构建时,汇总配置如下所示:
{
input: 'src/index.js',
output: {
file: 'dist/lib.esm.js',
format: 'esm',
}
(当然,我正在避免所有转译丑陋的插件,我认为它们会对这个问题造成干扰)
所以这个构建看起来不错,而且可以工作,但是...
- 使用起来很不方便:
import { components } from 'lib'
const { Comp1 } = components
- 这个构造可能也会在使用时破坏 tree shaking,因为我们导入了完整的
components
对象,而只需要 Comp1
。
我知道我不应该关心 tree shaking,而是提供一个 能够进行 tree shaking 的 库,这就是它的意义所在。当使用最简单的@vue/cli 模板测试我的构建时,整个库都被导入了,甚至@vue/cli 声称已经启用了开箱即用的 webpack-treeshaking 功能。
我不介意构建单独的文件而不是一个大的 esm 构建,但据我所知,使用 tree shaking 构建一个文件是可能的。我担心构建单独的文件是 CompA
可能在内部需要 CompB
,如果用户也需要 CompB
,在这种情况下它可能会在构建中被复制(如,一个外部使用版本和一个内部使用版本)。
我不知道如何进行优化。非常欢迎任何指针。
至于现在,我能找到的唯一有效解决方案是在 dist/
文件夹内的同一树结构中单独构建所有文件。我决定构建文件以提供 Vue 文件格式样式块,而无需最终消费者进一步构建或配置。
构建后的样子:
/src
/index.js
/components
/index.js
/component1
/index.js
/Comp.vue
...
/componentN
/index.js
/Comp.vue
/directives
/index.js
/directive1
/index.js
...
/directiveN
/index.js
/dist
/index.js
/components
/index.js
/component1
/index.js
...
/componentN
/index.js
/directives
/index.js
/directive1
/index.js
...
/directiveN
/index.js
我创建了一个小的递归函数来查找所有 'index.js' 并将此列表与汇总多入口点功能一起使用。希望汇总会创建所有子文件夹,因此不需要检查或 mkdir -p
.
// shorthand utility for 'find all files recursive matching regexp (polyfill for webpack's require.context)'
const walk = (directory, regexp) => {
let files = readdirSync(directory)
if (directory.includes('/examples'))
return []
return files.reduce((arr, file) => {
let path = `${directory}/${file}`
let info = statSync(path)
if (info.isDirectory())
return arr.concat(walk(path, regexp))
else if (regexp.test(file))
return arr.concat([path])
else
return arr
}, [])
}
// ...
const esm = walk(`${__dirname}/src`, /^index\.js$/)
.map(file => ({
input: file,
output: {
format: 'esm',
file: file.replace(`${__dirname}/src`, CONFIG.module)
},
...
}))
流程的最后一部分是 copy/paste package.json
进入 dist/
,cd
进入 npm publish
......这是集成到我们的 CI 任务中,因为它与汇总或构建没有直接关系,而是与发布相关。
它并不完美,但由于缺乏输入,这是我找到的唯一方法。
我希望它能帮助某人。
我想就如何构建一个易于使用和 tree-shaking 优化的构建提出建议。我正在使用 rollup 打包一个由多个组件组成的 UI 库。
我的架构是:
/src
/index.js
/components
/index.js
/component1
/index.js
/Comp.vue
...
/componentN
/index.js
/Comp.vue
/directives
/index.js
/directive1
/index.js
...
/directiveN
/index.js
src/components/index.js
看起来像
export { default as Comp1 } from './component1
...
export { default as CompN } from './componentN
src/directives/index.js
看起来像
export { default as Directive1 } from './directive1
...
export { default as DirectiveN } from './directiveN
每个内部index.js
只是为了方便而绑定,比如
import Comp from './Comp.vue'
export default Comp`
最后 src/index.js
将收集所有内容:
import { * as components } from './components'
import { * as directives } from './directives'
export { components, directives }
构建时,汇总配置如下所示:
{
input: 'src/index.js',
output: {
file: 'dist/lib.esm.js',
format: 'esm',
}
(当然,我正在避免所有转译丑陋的插件,我认为它们会对这个问题造成干扰)
所以这个构建看起来不错,而且可以工作,但是...
- 使用起来很不方便:
import { components } from 'lib'
const { Comp1 } = components
- 这个构造可能也会在使用时破坏 tree shaking,因为我们导入了完整的
components
对象,而只需要Comp1
。
我知道我不应该关心 tree shaking,而是提供一个 能够进行 tree shaking 的 库,这就是它的意义所在。当使用最简单的@vue/cli 模板测试我的构建时,整个库都被导入了,甚至@vue/cli 声称已经启用了开箱即用的 webpack-treeshaking 功能。
我不介意构建单独的文件而不是一个大的 esm 构建,但据我所知,使用 tree shaking 构建一个文件是可能的。我担心构建单独的文件是 CompA
可能在内部需要 CompB
,如果用户也需要 CompB
,在这种情况下它可能会在构建中被复制(如,一个外部使用版本和一个内部使用版本)。
我不知道如何进行优化。非常欢迎任何指针。
至于现在,我能找到的唯一有效解决方案是在 dist/
文件夹内的同一树结构中单独构建所有文件。我决定构建文件以提供 Vue 文件格式样式块,而无需最终消费者进一步构建或配置。
构建后的样子:
/src
/index.js
/components
/index.js
/component1
/index.js
/Comp.vue
...
/componentN
/index.js
/Comp.vue
/directives
/index.js
/directive1
/index.js
...
/directiveN
/index.js
/dist
/index.js
/components
/index.js
/component1
/index.js
...
/componentN
/index.js
/directives
/index.js
/directive1
/index.js
...
/directiveN
/index.js
我创建了一个小的递归函数来查找所有 'index.js' 并将此列表与汇总多入口点功能一起使用。希望汇总会创建所有子文件夹,因此不需要检查或 mkdir -p
.
// shorthand utility for 'find all files recursive matching regexp (polyfill for webpack's require.context)'
const walk = (directory, regexp) => {
let files = readdirSync(directory)
if (directory.includes('/examples'))
return []
return files.reduce((arr, file) => {
let path = `${directory}/${file}`
let info = statSync(path)
if (info.isDirectory())
return arr.concat(walk(path, regexp))
else if (regexp.test(file))
return arr.concat([path])
else
return arr
}, [])
}
// ...
const esm = walk(`${__dirname}/src`, /^index\.js$/)
.map(file => ({
input: file,
output: {
format: 'esm',
file: file.replace(`${__dirname}/src`, CONFIG.module)
},
...
}))
流程的最后一部分是 copy/paste package.json
进入 dist/
,cd
进入 npm publish
......这是集成到我们的 CI 任务中,因为它与汇总或构建没有直接关系,而是与发布相关。
它并不完美,但由于缺乏输入,这是我找到的唯一方法。 我希望它能帮助某人。