vite的实践

发表于 2024-04-11
更新于 2024-05-23
分类于 技术专栏
阅读量 133
字数统计 6946

1、前言

为了让打包轻量级上线,我们现有的项目打包工具全部转vite,目前在用的是vite@4,官网最新版本已经是v5了,不过不影响目前我们项目的一些时间。这里着重讲讲我们在vite上的一些实践遇到的问题以及如何处理的。

2、实践经验

2.1、解决引用antd@3版本报错的问题

因为现存有些项目依赖的包有很旧的,比如antd@3,这个组件库依赖于图标库(3版本的antd的图标没有拆开的,打包依赖在antd3里面),又因为@ant-design/icons编译出来的语法vite压根不兼容,因此我们用了一些Hack的手段,具体解决方法可以看社区这个链接:

解决ant-design/icons引用错误的问题

2.2、解决required is not define 的问题

本质是因为vite使用的esmodule的模块编译方式,require是commonjs的语法,因此之间就存在gap,还好社区给了对应的workaround:

2.3、vite编译中import.meta的TreeShaking

实践证明想通过使用import.meta来做到精简代码的话,请使用下面这种表达式:

1import.meta.env.MODE === 'A' || import.meta.env.MODE === 'B'

而不是:

1['A', 'B'].includes(import.meta.env.MODE)

2.4、多业务场景的项目打包

应该很多公司存在同一个项目支撑多种业务场景的情况,然后一些业务场景有自己特殊定制的页面,这个时候就需要进行一些项目的特殊改造,我们给出的实践是:

不同场景使用不同的打包入口,结合ts,可以做到完美契合;

假设有场景A和场景B,二者有一些公共文件,我们定义的整体项目结构是这样的:

1├── README.md 2├── tsconfig.json 3├── base.vite.config.ts 4├── A.vite.config.ts 5├── B.vite.config.ts 6└── src 7 ├── core // 所有场景共用的目录,公共文件都放在这里 8 │   ├── api 9 │   ├── assets 10 │   ├── components 11 │   ├── constants 12 │   ├── features 13 │   ├── hooks 14 │   ├── pages 15 │   ├── router 16 │   ├── store 17 │   ├── styles 18 │   └── utils 19 ├── A 20    │   ├── App.tsx 21    │   ├── apis 22    │   ├── declare.d.ts 23    │   ├── index.html 24    │   ├── main.tsx 25    │   ├── pages 26    │   ├── public 27    │   ├── router 28    │   ├── store 29    │   └── tsconfig.json 30 └── B 31    │   ├── App.tsx 32    │   ├── apis 33    │   ├── declare.d.ts 34    │   ├── index.html 35    │   ├── main.tsx 36    │   ├── pages 37    │   ├── public 38    │   ├── router 39    │   ├── store 40    │   └── tsconfig.json

然后为了解决ts的类型问题,每个场景下都有自己对应的tsconfig.json,并且是基于根目录的tsconfig.json,文件内容主要是:

1{ 2 "extends": "../../tsconfig.json", 3 "compilerOptions": { 4 "baseUrl": ".", 5 "paths": { 6 "@/*": ["*"], 7 "apis/*": ["apis/*"], 8 "hooks/*": ["hooks/*"], 9 "utils/*": ["utils/*"], 10 "router/*": ["router/*"], 11 "store/*": ["store/*"], 12 "components/*": ["components/*"], 13 "features/*": ["features/*"], 14 "styles/*": ["styles/*"], 15 "assets/*": ["assets/*"], 16 "@core/*": ["../core/*"] 17 } 18 }, 19 "include": [ 20 "*", 21 "./*.d.ts", 22 "*/*.ts", 23 "*/*/*.ts", 24 "*/*.tsx", 25 "*/*/*.tsx", 26 "*/*/*/*.tsx", 27 "*/*/*/*/*.tsx" 28 ] 29} 30

从而保证了整体的代码类型都是可解析的。

PS:之前本来是想通过lerna来实现的,但是发现lerna依赖的包更新的话不会自动更新,并且在项目初期,依赖包可能会频繁更新,这样带来的开发体验太差,所以才转成这种模式;

2.5、引入3D的一些静态模型

之前有个3D的组件会在多个项目中使用,为了减少每个项目都去引入3D组件的模型以及GLSL语言,于是想到通过vite打包的时候,直接集成进去,在网上就找到了对应的配置:

1import react from '@vitejs/plugin-react'; 2import { defineConfig } from 'vite'; 3import dts from 'vite-plugin-dts'; 4import visualizer from 'rollup-plugin-visualizer'; 5 6export default defineConfig(async () => { 7 // 这个是为了打包GLSL文件的 8 const glsl = (await import('vite-plugin-glsl')).default; 9 10 return { 11 assetsInclude: ['**/*.obj', '**/*.mtl'], 12 plugins: [ 13 glsl(), 14 react(), 15 dts({ 16 insertTypesEntry: true, 17 }), 18 visualizer({ 19 open: true, 20 gzipSize: true, 21 brotliSize: true, 22 }), 23 ], 24 css: { 25 preprocessorOptions: { 26 less: { 27 // 支持内联 JavaScript 28 javascriptEnabled: true, 29 }, 30 }, 31 }, 32 // 添加库模式配置 33 build: { 34 outDir: 'dist', 35 sourcemap: true, // 输出单独 source文件 36 minify: false, 37 rollupOptions: { 38 external: ['react', 'react-dom', 'antd'], 39 output: { 40 globals: { 41 react: 'react', 42 antd: 'antd', 43 'react-dom': 'react-dom', 44 45 }, 46 }, 47 }, 48 lib: { 49 entry: './src/index.ts', 50 name: 'HDmap', 51 fileName: (format) => `index.${format}.js`, 52 formats: ['es'], 53 }, 54 }, 55 }; 56}); 57

组件内部的使用代码如下:

1import blueTruckMtl from '../models/xx.mtl?url'; 2import redTruckMtl from '../models/xxx.mtl?url'; 3import grayTruckMtl from '../models/xxxx.mtl?url'; 4import truckObj from '../models/truck.obj?url'; 5 6import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader'; 7import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; 8 9// 接着直接使用即可: 10const objLoader = new OBJLoader(); 11const material = (await loadMTL(blueTruckMtl)) as MTLLoader.MaterialCreator; 12objLoader.setMaterials(material); 13objLoader.load(truckObj)

PS:最后模型还是没有采用打包进去的方式,因为模型太大了,导致组件库膨胀了,换成了把所有模型放在public目录下,跟随包出去,但不是放在js文件里面,外部应用使用的时候用下面的配置即可:

1import { defineConfig } from 'vite'; 2import copy from 'rollup-plugin-copy'; 3 4// https://vitejs.dev/config/ 5export default defineConfig({ 6 // 其他配置 7 // 使用copy插件在编译的时候把组件包里的模型取出 8 plugins: [ 9 copy({ 10 targets: [ 11 { src: 'node_modules/你的包的名称/dist/*.mtl', dest: 'public' }, 12 { src: 'node_modules/你的包的名称/dist/*.obj', dest: 'public' }, 13 { src: 'node_modules/你的包的名称/dist/**/*.json', dest: 'public' }, 14 ], 15 hook: 'buildStart', 16 }), 17 ], 18}); 19

2.6、拆分你的组件,从而支持按需加载

很多场景你打包出来的组件,不希望全部被应用方给引用,导致应用的体积变大,这个时候就需要在你自己开发的组件上,加下配置,让打包出来的文件拆解成很多js,如下图:

或者是这样的:

标准的vite.config.ts是这样的:

1import { defineConfig } from 'vite'; 2import react from '@vitejs/plugin-react-swc'; 3import * as path from 'path'; 4import typescript from '@rollup/plugin-typescript'; 5 6const resolvePath = (str: string) => path.resolve(__dirname, str); 7export default defineConfig({ 8 server: { 9 host: '0.0.0.0', 10 port: 8080, 11 }, 12 plugins: [react()], 13 resolve: { 14 alias: { 15 '@': resolvePath('src'), 16 packages: resolvePath('src/packages'), 17 stories: resolvePath('src/stories'), 18 test: resolvePath('src/test'), 19 }, 20 }, 21 css: { 22 preprocessorOptions: { 23 less: { 24 // 支持内联 JavaScript 25 javascriptEnabled: true, 26 }, 27 }, 28 }, 29 build: { 30 lib: { 31 entry: 'src/packages/index.ts', 32 name: 'xxxxxx', 33 fileName: (format) => `index.${format}.js`, 34 formats: ['es'], 35 }, 36 rollupOptions: { 37 external: ['react', 'react-dom'], 38 output: { 39 preserveModules: true, 40 preserveModulesRoot: 'src', 41 dir: 'dist/', 42 format: 'es', 43 globals: { 44 react: 'react', 45 'react-dom': 'react-dom', 46 47 }, 48 }, 49 plugins: [ 50 typescript({ 51 tslib: path.resolve('typescript'), 52 declaration: true, 53 exclude: ['src/stories/*', 'src/App.tsx', 'src/main.tsx', 'src/test/*'], 54 outDir: resolvePath('dist'), 55 }), 56 ], 57 }, 58 }, 59}); 60

公众号关注一波~

微信公众号

关于评论和留言

如果对本文 vite的实践 的内容有疑问,请在下面的评论系统中留言,谢谢。

网站源码:linxiaowu66 · 豆米的博客

Follow:linxiaowu66 · Github