introduce
Let me share with you a Vite multi-entry project that I recently built for the company (there is only an empty shelf for confidentiality issues)
github link: https://github.com/duKD/vue-vite-multiple-entry
Project structure
├── dist 打包后的静态资源目录
└── src 项目资源目录
└── assets 项目静态资源
└── hooks 全局hooks
├── utils 全局方法公共库
└── utils1.ts 全局公共方法
└── constants.ts 全局公共常量
├── components 公共组件
├── styles 公共样式模块
├── pages 页面模块
├── xxx 页面模块A
├── apis 接口定义
├── components 页面组件
└── router 路由配置
└── store store配置
└── common 模块公共库
└── utils.ts 模块公共工具方法
└── constants.ts 模块常量
└── eventMap.ts 模块埋点枚举
└── views 模块页面
└── App.vue 入口根节点
└── index.html 入口页面
└── main.ts 入口页面文件
├── xxx 页面模块B
├── apis 接口定义
├── components 页面组件
└── router 路由配置
└── store store配置
└── common 模块公共库
└── utils.ts 模块公共工具方法
└── constants.ts 模块常量
└── eventMap.ts 模块埋点枚举
└── views 模块页面
└── App.vue 入口根节点
└── index.html 入口页面
└── main.ts 入口页面文件
├── xxx 初始化入口文件
├── public 该文件下的 模块 会直接移到 dist 根目录下 不会被打包处理
├── types 依赖库类型定义
└── .eslintignore eslint忽略文件配置
└── .eslintrc.cjs eslint规则配置
└── .gitignore gitignore配置
└── .prettierignore prettier忽略文件配置
└── .prettierrc.cjs prettier文件配置
└── .vue.config.ts 项目打包配置文件
As shown below:
Package configuration
// vite.config
import {
UserConfig, ConfigEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import {
resolve, join } from 'path'
import glob from 'glob'
import legacy from '@vitejs/plugin-legacy'
import checker from 'vite-plugin-checker'
const assetsPath = (path: string) => {
return join('static', path)
}
const getEntryPath = () => {
const pageEntry: any = {
}
glob.sync('./src/pages/**/index.html').forEach((entry: string) => {
const pathArr: string[] = entry.split('/')
const name: string = pathArr[pathArr.length - 2]
pageEntry[name] = join(process.cwd(), `/src/pages/${
name}/index.html`)
})
console.log(pageEntry)
return pageEntry
}
// 指定 某个路径下的 公共模块 打包成 一个 chunk
const chunkPath = ['src/utils']
// https://vitejs.dev/config/
export default ({
command, mode }: ConfigEnv): UserConfig => {
const isBuild = command === 'build'
return {
root: './src/pages',
base: '/',
resolve: {
alias: [
{
find: '@',
replacement: resolve(__dirname, 'src')
}
]
},
plugins: [
vue(),
// 会根据 浏览器环境 自动 引入垫片 兼容
legacy({
targets: [
'defaults',
'ie >= 11',
'chrome 52',
'iOS >= 9',
'Android >= 5'
], //需要兼容的目标列表,可以设置多个
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
renderLegacyChunks: true,
polyfills: [
'es.symbol',
'es.array.filter',
'es.promise',
'es.promise.finally',
'es/map',
'es/set',
'es.array.for-each',
'es.object.define-properties',
'es.object.define-property',
'es.object.get-own-property-descriptor',
'es.object.get-own-property-descriptors',
'es.object.keys',
'es.object.to-string',
'web.dom-collections.for-each',
'esnext.global-this',
'esnext.string.match-all'
]
}),
// 开启ts 检测不通过 显示到浏览器
!isBuild &&
checker({
vueTsc: true
})
],
build: {
outDir: resolve(process.cwd(), 'dist'), // 指定输出路径(相对于 项目根目录)
sourcemap: false, // 构建后是否生成 source map 文件
chunkSizeWarningLimit: 1500, // 规定触发警告的 chunk(文件块) 大小
assetsDir: 'static',
reportCompressedSize: false, //禁用 gzip 压缩大小报告
minify: 'esbuild',
rollupOptions: {
// 自定义底层的 Rollup 打包配置
input: getEntryPath(),
output: {
entryFileNames: (chunkInfo) => {
return `${
chunkInfo.name}/js/[name]-[hash].js`
},
chunkFileNames: assetsPath('chunk/[name]-[hash].js'),
assetFileNames: assetsPath('assets/[ext]/[name]-[hash].[ext]'),
compact: true,
// 多入口 打包 默认情况 在多个 入口 使用的公共模块(非第三方模块) 次数超过1 就会生成一个 chunk
// 优化 chunk 过多 碎片 化 浪费请求资源
/**
* 1. 第三方模块 vue 系列 生成一个 chunk 其它 单独生成对应的 chunk
* 2. 在代码中的公共模块 src 下的 可以 在 chunkPath 去设置 合成 chunk 路径
* src/utils 代表 这个文件夹 下 使用的 会在一个 chunk 下 命名 src-utils-[hash].js
*/
manualChunks: (id: string) => {
if (id.includes('node_modules')) {
const temp = id.split('node_modules')[1]
if (temp.includes('vue')) {
// vue 系列 单独 抽离 一个 chunk
return 'vue-vendor'
}
// 根据项目实际情况 去做选择
// 默认 第三方 库 es module 规范 支持 tree-shaking 只会 将部分代码注入 业务代码中 尽量使用es 规范的库
// 其它第三方库 生成 chunk
return 'other-vendor'
// 手动指定第三方库 是否单独生成 chunk
// 其余 第三方共用模块 再 单独生成 chunk
// return id
// .toString()
// .split("node_modules/")[1]
// .split("/")[0]
// .toString(); // 拆分多个vendors
} else {
const len = chunkPath.length
for (let i = 0; i < len; ++i) {
if (id.includes(chunkPath[i])) {
return chunkPath[i].replace(/\//, '-')
}
}
}
}
}
},
emptyOutDir: true
},
css: {
preprocessorOptions: {
less: {
additionalData: `@import "${
resolve(
__dirname,
'src/styles/variable.less'
)}";`,
javascriptEnabled: true
}
}
}
}
}
Integrate eslint prettier
第一步 下载 eslint prettier和对应插件 并初始化
npm i -D eslint eslint-plugin-promise eslint-plugin-vue @typescript-eslint/parser @typescript-eslint/eslint-plugin
npm i -D prettier eslint-config-prettier eslint-plugin-prettier
//.eslintrc.cjs
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:vue/vue3-essential",
"plugin:@typescript-eslint/recommended",
],
overrides: [],
parser: "vue-eslint-parser",
parserOptions: {
ecmaVersion: "latest",
parser: "@typescript-eslint/parser",
sourceType: "module",
},
plugins: ["vue", "@typescript-eslint"],
rules: {
// 关闭名称校验
"vue/multi-word-component-names": "off",
"no-unused-vars": "off",
"vue/no-unused-vars": "off",
"no-useless-escape": "off",
"@typescript-eslint/no-explicit-any": "off", //关闭any类型警告
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-empty-function": "off"
},
};
//.eslintignore
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.local
/bin
Dockerfile
第二步 使用 eslint 格式化代码
在package.json 增加 命令行
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix"
执行 npm run lint 根据提示 解决 错误 或者 取消相应检查规则 .eslintrc.cjs上 rules 配置
第三步 使用 prettier 格式化代码
在package.json 增加 命令行
"format": "prettier --write \"./**/*.{html,vue,ts,js,json,md}\""
第四步 配置 vscode 代码保存 自动化代码
// settings.json
{
"editor.detectIndentation": false,
// 保存的时候自动格式化
"editor.formatOnSave": true,
// 开启自动修复
"editor.codeActionsOnSave": {
"source.fixAll": false,
"source.fixAll.eslint": true
},
"editor.defaultFormatter": "esbenp.prettier-vscode"
}