|
| 1 | +--- |
| 2 | +title: Vite 疑难杂症 |
| 3 | +date: 2025-04-15 10:52:55 |
| 4 | +category: |
| 5 | +tags: |
| 6 | +cover: |
| 7 | +--- |
| 8 | + |
| 9 | +在 2022 年初投产了第一个 Vite 应用到产线,陆续处理的问题 Case,挑选一些记录下来。 |
| 10 | + |
| 11 | +## 应用中需要支持 `require` 语法 |
| 12 | + |
| 13 | +应用代码中,通常不再建议使用 `require`,应当都替换为 `import`. |
| 14 | + |
| 15 | +但是,若为迁移旧代码或其它原因,社区有多款插件可以选用。 |
| 16 | + |
| 17 | +简单的场景推荐:https://github.com/wangzongming/vite-plugin-require |
| 18 | + |
| 19 | +如果是三方依赖包的产物中包含了 `require()` 代码呢? |
| 20 | + |
| 21 | +这种场景更加复杂一些,在 esbuild 预构建时可能遇到模块导出的值不符合预期,在调研对比多个社区方案后,推荐考虑使用以下插件: |
| 22 | + |
| 23 | +https://github.com/vite-plugin/vite-plugin-commonjs |
| 24 | + |
| 25 | +## lib 模式编译,如何引入 polyfill? |
| 26 | + |
| 27 | +在打包 App 应用时可以依靠 [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) 处理 Polyfill,而 lib 模式编译类库时,不会引入 Polyfill。 |
| 28 | + |
| 29 | +推荐使用 Rollup 插件,通过 Babel 在最后阶段再处理 Polyfill。 |
| 30 | + |
| 31 | +```typescript |
| 32 | +import { defineConfig } from 'vite'; |
| 33 | +import { getBabelOutputPlugin } from '@rollup/plugin-babel'; |
| 34 | + |
| 35 | +export default defineConfig({ |
| 36 | + build: { |
| 37 | + rollupOptions: { |
| 38 | + plugins: [ |
| 39 | + /** |
| 40 | + * Running Babel on the generated code: |
| 41 | + * https://github.com/rollup/plugins/blob/master/packages/babel/README.md#running-babel-on-the-generated-code |
| 42 | + * |
| 43 | + * Transforming ES6+ syntax to ES5 is not supported yet, there are two ways to do: |
| 44 | + * https://github.com/evanw/esbuild/issues/1010#issuecomment-803865232 |
| 45 | + * We choose to run Babel on the output files after esbuild. |
| 46 | + * |
| 47 | + * @vitejs/plugin-legacy does not support library mode: |
| 48 | + * https://github.com/vitejs/vite/issues/1639 |
| 49 | + */ |
| 50 | + getBabelOutputPlugin({ |
| 51 | + allowAllFormats: true, |
| 52 | + presets: [ |
| 53 | + [ |
| 54 | + '@babel/preset-env', |
| 55 | + { |
| 56 | + useBuiltIns: false, |
| 57 | + exclude: ['transform-typeof-symbol'], |
| 58 | + modules: false, |
| 59 | + }, |
| 60 | + ], |
| 61 | + ], |
| 62 | + plugins: [ |
| 63 | + [ |
| 64 | + '@babel/plugin-transform-runtime', |
| 65 | + { |
| 66 | + corejs: false, |
| 67 | + // version: require('@babel/runtime').version, |
| 68 | + }, |
| 69 | + ], |
| 70 | + ].filter(Boolean), |
| 71 | + }), |
| 72 | + ], |
| 73 | + }, |
| 74 | + }, |
| 75 | +}); |
| 76 | +``` |
| 77 | + |
| 78 | +## Vite lib 模式打包时,静态资源会被内联([官方解释](https://cn.vite.dev/config/build-options.html#build-assetsinlinelimit)),如何处理? |
| 79 | + |
| 80 | +当我们使用 Vite 编译组件、类库时,此问题暴露尤其明显。例如组件中使用的某几张图片,留待使用该组件的应用打包应属最佳,否则,大量的图片被内联在 js 代码中,会严重影响加载速度。 |
| 81 | + |
| 82 | +在我们的场景下此问题十分重要,社区内没有可使用的方案,layne 同学编写了以下插件完美解决问题。 |
| 83 | + |
| 84 | +https://github.com/laynezh/vite-plugin-lib-assets |
| 85 | + |
| 86 | +- `iife` 资源路径转拼接指定的 `publicUrl` |
| 87 | +- `esm` 转换为相对路径引入 |
| 88 | +- `commonjs` 转换为相对路径引入 |
| 89 | + |
| 90 | +```typescript |
| 91 | +import { defineConfig } from 'vite'; |
| 92 | +import assetsPlugin from '@laynezh/vite-plugin-lib-assets'; |
| 93 | + |
| 94 | +export default defineConfig({ |
| 95 | + plugins: [ |
| 96 | + assetsPlugin({ |
| 97 | + name: '[name].[contenthash:8].[ext]', |
| 98 | + limit: 1024 * 8, |
| 99 | + publicUrl: undefined, |
| 100 | + }), |
| 101 | + ], |
| 102 | +}); |
| 103 | +``` |
| 104 | + |
| 105 | +## commonjs 模块中引用的资源应原样输出 |
| 106 | + |
| 107 | +```typescript |
| 108 | +import { defineConfig } from 'vite'; |
| 109 | + |
| 110 | +export default defineConfig({ |
| 111 | + build: { |
| 112 | + commonjsOptions: { |
| 113 | + /** |
| 114 | + * https://github.com/rollup/plugins/tree/master/packages/commonjs#requirereturnsdefault |
| 115 | + * |
| 116 | + * require('./images/123.png') => import Img123 from './images/123.png' |
| 117 | + * |
| 118 | + * and './images/123.png' 会被 vite 处理成 base64 格式实现载入 |
| 119 | + */ |
| 120 | + requireReturnsDefault(id) { |
| 121 | + const [pureId] = id.split('?', 2); |
| 122 | + return commonjsAssetsFilter(pureId); |
| 123 | + }, |
| 124 | + }, |
| 125 | + }, |
| 126 | +}); |
| 127 | +``` |
| 128 | + |
| 129 | +## 修改 lib 模式输出的样式文件名 |
| 130 | + |
| 131 | +不同于修改 js 文件输出的名称,样式文件需要不一样的处理方式。 |
| 132 | + |
| 133 | +```typescript |
| 134 | +import defineConfig from 'vite'; |
| 135 | + |
| 136 | +export default defineConfig({ |
| 137 | + build: { |
| 138 | + rollupOptions: { |
| 139 | + output: { |
| 140 | + assetFileNames(assetInfo) { |
| 141 | + // https://github.com/vitejs/vite/issues/4863 |
| 142 | + if (!ignoreStyles && assetInfo.name === 'style.css') { |
| 143 | + return `${fileName}.css`; |
| 144 | + } |
| 145 | + return assetInfo.name; |
| 146 | + }, |
| 147 | + }, |
| 148 | + }, |
| 149 | + }, |
| 150 | +}); |
| 151 | +``` |
0 commit comments