personal website.
Table of contents
Note
使用 vite+vue3
构建项目
测试用仓库 进入
app/website
文件夹下后进行bun run build
即可
import xx from 'xxx'
会合并, 异步引用() => import('xxx')
会分包a
,b
,c
三个文件。a
同步引用b
, b
同步引用c
, 同步引用可以平铺, 这其实相当于直接在a
中同步引用了b
和c
。这时如果在a中对c
进行异步引用则会导致冲突, 使得c
无法被分包(因为c
已经在同一个地方a
中被同步引用)a
异步引用b
, b
同步引用c
, 这相当于a
中没有任何同步引用, 但有另一个异步分支引用b
。这时在a
中同步引用c
的话,c
会与a
进行合并,而在b
中则通过同步引用这个合并后的文件获取c
a
异步引用b
, b
异步引用c
。这时在a
中同步引用c
,c
还是会与a
进行合并,而在b
中则通过__vitePreload
异步引用这个合并后的文件获取c
export
可以被保留named export
, 例如export default {}
和export const/function xxx = something
等变为:const a = {};
const o = something;
export { a as default, o as xxx };
而通过同步引用的包经过其他手段进行分包(如manualChunks
)则无法保留named export
, 同样引用上面的例子,打包后可能会变为:const a = {};
const o = something;
export { a as u, o as p };
通过manualChunks
实现类似组件库分割组件的想法不可行, 最好通过每个组件一个入口文件实现分割, 推荐通过配置build.lib
来实现manualChunks
中进行分包 则无法保留 named export
vite
是否存在chunk
大小上限限制或其他的同步引用分包策略,理论上来说所有同步引用都会被打成一个chunk
?Note
如果该包作为组件使用而不是网页则推荐使用build.lib
模式配置并打包
当然也可以自己写rollup
配置文件, 但两种方式都需要自己写点脚本代码
项目src
下的结构:
.
├── assets
│ └── vue.svg
├── components
│ └── i18n
│ ├── index.ts
│ └── lang
│ ├── en.ts
│ └── zh.ts
├── index.ts
└── vite-env.d.ts
这里在entry中配置了所有语言文件及其他入口,并且在fileName中通过matchLocaleLang
来匹配语言文件的名字并加上路径
function getLocaleMap() {
const cwd = "./src/components/i18n/lang/";
const resList = Array.from(
new Bun.Glob("*.ts").scanSync({
cwd,
}),
).map((v) => path.join(cwd, v));
const resMap: Record<string, string> = {};
const tsPattern = /(.*)\.ts$/i;
resList.forEach((v) => {
console.log(v);
const name = "locale_" + path.basename(v).replace(tsPattern, "$1");
resMap[name] = v;
});
console.log(resMap);
return resMap;
}
function matchLocaleLang(name: string) {
const localePathBase = "i18n/";
const localeLangPath = "lang/";
// local lang
const localPattern = /^locale_(.*)/i;
const res = localPattern.exec(name);
if (res && res[1]) return path.join(localePathBase, localeLangPath, res[1]);
// locale
if (name === "locale") return path.join(localePathBase, name);
// other
return name;
}
export default defineConfig(() => {
return {
build: {
lib: {
entry: {
index: "src/index.ts",
locale: "src/components/i18n/index.ts",
...getLocaleMap(),
},
fileName(format, entryName) {
entryName = matchLocaleLang(entryName);
console.log(entryName);
return `${entryName}.${format}.js`;
},
formats: ["es"],
},
},
};
});
打包后得到:
.
├── components
│ └── i18n
│ ├── index.d.ts
│ └── lang
│ ├── en.d.ts
│ └── zh.d.ts
├── i18n
│ ├── lang
│ │ ├── en.es.js
│ │ └── zh.es.js
│ └── locale.es.js
├── index.d.ts
├── index.es.js
└── vite.svg
tsc输出的d.ts与js路径不同没事,可以通过package.json
中的exports
配置来实现:
{
"type": "module",
"exports": {
".": {
"import": "./dist/index.es.js",
"types": "./dist/index.d.ts"
},
"./i18n/lang/*": {
"types": "./dist/components/i18n/lang/*.d.ts",
"import": "./dist/i18n/lang/*.es.js"
},
},
}
这里我指明了入口和i18n/lang/*
, types
和import
分别指定d.ts和js的路径, 但需要注意的是*
只能匹配一次, 不能实现类似**/*.xxx
的匹配
这样就实现了分开导出且保留named export