需求
业务需要根据不同的产品pid打包成多个包,对于vite启动的单页面应用而言,一般一个入口对应一个出口,vite会以根目录index.html作为应用入口和依赖图,解析并打包。对于多出口以官网给出的案例及结合网上案例参考,进行实践。
vite的打包底层是rollup,因此需要参考rollupjs文档的配置项进行开发实践,观察不同配置打包的结果进行分析。
参考
vite2+vue3+typescript按需打包多页面项目
方案1: 基于官方的配置(多入口配置默认output)
// 读取/src/views pid文件名长度 得到pid名的数组
let requirePidViews = fs.readdirSync('./src/views').filter(pid => pid.length === 32);
// input 入口配置Object|Array
const buildInputConfigs = {};
// 循环遍历
requirePidViews.forEach(pid => {
// 配置多个入口模板打包
const htmlUrl = resolve(__dirname, `src/views/${pid}/index.html`);
// buildInputConfigs.push(htmlUrl); // 数组的形式
buildInputConfigs[pid] = htmlUrl; // 对象的形式
});
// 配置打包input
defineConfig({
build: {
base: './',
target: 'es2015',
rollupOptions: {
input: buildInputConfigs
}
}
})
基于官方的配置结果(如下图)
问题:
1.不能分别把不同pid下的assets资源打包到pid/assets下
2.路径多了几层如dist/src/views/pid/index.html
理想的是dist/pid/assets/*,dist/pid/index.html,dist/pid/favicon
解决参考:
vite 多页面配置的root等路径配置,目前未能成功配置
方案2: 基于参考vite2+vue3+typescript按需打包多页面项目的配置(默认input多出口)
// 读取/src/views pid文件名长度 得到pid名的数组
let requirePidViews = fs.readdirSync('./src/views').filter(pid => pid.length === 32);
// output出口配置数组Array
const buildOutputConfigs = [];
// 循环遍历
requirePidViews.forEach(pid => {
// 配置多出口打包
buildOutputConfigs.push({
dir: `dist/${pid}/`,
assetFileNames: '[ext]/[name]-[hash].[ext]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
});
});
// 配置打包input
defineConfig({
build: {
base: './',
target: 'es2015',
rollupOptions: {
output: buildOutputConfigs
}
}
})
const fs = require('fs');
const distFiles = fs.readdirSync('dist').filter(item => item !== 'favicon.ico');
distFiles.forEach(pid => {
fs.copyFileSync('dist/favicon.ico', `dist/${pid}/favicon.ico`);
});
基于基于参考vite2+vue3+typescript按需打包多页面项目的配置结果
本次还试验了同时input为对象、output为对象outputbanneroutputfooter****
defineConfig({
build: {
base: './',
target: 'es2015',
rollupOptions: {
input: {
pid1: 'src/views/pid1/index.html',
pid2: 'src/views/pid2/index.html'
},
output: {
pid1: 'pid1/',
pid2: 'pid2/
}
}
}
})
本次还试验了同时input为数组、output为数组
方案3: 基于参考vite2+vue3+typescript按需打包多页面项目的配置(每次打包一个)
const target = 'http://xxx.com';
// 读取/src/views pid文件名长度 得到pid名的数组
// 来自package.json如{ "buildPid": "vite build --" } 执行时npm run build xxxxx
const pid = process.argv[process.argv.length - 1]; // npm run build xxxxx 中的xxxx
// 根据src/views/*获取列表的pid名数组
const viewsFoldUrl = resolve(__dirname, 'src/views/');
// 过滤是pid的
const pidViews = fs.readdirSync(viewsFoldUrl).filter(pid => pid.length === 32);
// 如果正在打包此pid则删除dist已删除的对应的包
if (pidViews.includes(pid)) {
fs.rmSync(resolve(__dirname, `dist/${pid}/`), { recursive: true, force: true });
}
// 根据终端分别为开发环境分别配置
export default defineConfig(({ mode }: ConfigEnv) => {
return pid === '--host'
? {
base: './',
build: {
target: 'es2015'
},
plugins: [
vue(),
Components({
resolvers: [ElementPlusResolver()]
}),
AutoImport({
resolvers: [ElementPlusResolver()]
}),
legacy({
targets: ['defaults', 'not IE 11'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
modernPolyfills: true
})
],
resolve: {
alias: [{ find: '@', replacement: resolve(__dirname, 'src') }]
},
css: {
preprocessorOptions: {
scss: {
charset: false,
additionalData: `@import "@/assets/style/variables.scss";@import "@/assets/style/mixins.scss";@import "@/assets/style/common.scss";`
}
}
},
server: {
host: 'localhost',
port: 8848,
proxy: {
'/api': {
target,
changeOrigin: true,
rewrite: path => path.replace(/^/api/, '/statice')
},
'/plugin': {
target,
changeOrigin: true
}
}
}
}
: {
root: `./src/views`, // 基于index.html的路径
publicDir: `${process.cwd()}/public`, //
base: '/',
build: {
target: 'es2015',
emptyOutDir: false, // 每次打包不清空
outDir: `${process.cwd()}/dist/`, //资源产出路径
assetsDir: `./${pid}/static/assets/`, // 无法被output识别的其他资源打包路径
rollupOptions: {
input: resolve(__dirname, `src/views/${pid}/index.html`), // 打包入口模板
output: {
assetFileNames: `${pid}/static/[ext]/[name]-[hash].[ext]`, // 静态资源块
chunkFileNames: `${pid}/static/js/[name]-[hash].js`, // chunk 块
entryFileNames: `${pid}/static/js/[name]-[hash].js` // 入口文件块
}
}
},
plugins: [
vue(),
Components({
resolvers: [ElementPlusResolver()]
}),
AutoImport({
resolvers: [ElementPlusResolver()]
}),
legacy({
targets: ['defaults', 'not IE 11'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
modernPolyfills: true,
renderLegacyChunks: true
})
],
resolve: {
alias: [{ find: '@', replacement: resolve(__dirname, 'src') }]
},
css: {
preprocessorOptions: {
scss: {
charset: false,
additionalData: `@import "@/assets/style/variables.scss";@import "@/assets/style/mixins.scss";@import "@/assets/style/common.scss";`
}
}
}
};
});
基于基于参考vite2+vue3+typescript按需打包多页面项目的配置结果(每次打包一个)
总结
方案1: 单一模板,多个output;assets无法进入到某个pid下,具有路由,某个pid会打包不用页面的代码
方案2: 多模板,单个output,每个pid都是完整的内容,具有路由,某个pid会打包不用页面的代码
方案3: 多模板,单个output,每个pid不再具备路由,某个pid不会打包不用页面的代码
疑惑
outDir,assetsDir,root,base等如何配置,它们之前的配置关系如何相互参照,最终页面如何引入资源,包括开发和生产环境,不是很清楚,在配置的时候比较困难,需要一个一个调整去验证,希望后期能找到合适的资源深入理解。