We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
相较于webpack,以rollup为基础的vite,基于浏览器的模块化无论是冷启动还是打包都是异常的快速。 之前大大小小也在三四个项目上使用过vite,体验下来还有局限性的。
这个问题主要是因为vite的核心是es module,简单的说就是依赖浏览器的模块化功能(import和export) 这里可以简单的看一下目前各浏览器对module的支持程度,很明显对于IE等传统浏览器打包后的代码是无法运行的。但是这个问题目前可以通过官方插件@vitejs/plugin-legacy来支持。
es module
相较于webpack成熟的社区生态,大部分问题都可以找到对应的库来解决,但是在这一点上,刚刚起步的vite很明显是做不到的。现阶段,如果想要在项目上使用,需要做好造轮子的心里准备。 举一个简单的例子,原先webpack的项目针对svg的加载,都是通过svg-sprite-loader来实现的。
const platform = process.platform; module.exports = { chainWebpack: config => { config.module .rule('icons') .test(/\.svg$/) .include.add(path.join(__dirname, 'src/assets/icon')) .end() .use('svg-sprite-loader') .loader('svg-sprite-loader') .options({ // symbolId: 'icon-[name]' symbolId: function(paths) { const res = paths.substr(path.join(__dirname, 'src/assets/icon').length + 1).split(platform === 'win32' ? '\\' : '/'); let symbolId = ''; res.forEach((item, index) => { if (index === 0) { symbolId += item; } else { symbolId += item.replace(/^./, item.slice(0, 1).toUpperCase()); } }) return `icon-${path.basename(symbolId, '.svg')}`; } }); } }
而vite很明显不能这样实现svg的动态加载。
import { Plugin } from 'vite'; import fs from 'fs'; import path from 'path'; function collectSvg(dir: string): string[] { const svgList = []; const dirents = fs.readdirSync(dir, { withFileTypes: true }) dirents.forEach(dirent => { if (dirent.isDirectory()) { svgList.push(...collectSvg(path.resolve(dir, dirent.name))); } else { const content = fs.readFileSync(path.resolve(dir, dirent.name)) .toString() .replace(/<svg([^>+].*?)/, ($1, $2) => { return `<symbol id=icon-${dirent.name.replace('.svg', '')} ${$2}` }) .replace('</svg>', '</symbol>'); svgList.push(content) } }) return svgList; } export function svgLoader(svgPath: string): Plugin { return { name: 'svg-loader', transformIndexHtml(html): string { const res = collectSvg(svgPath); return html.replace('<body>', ` <body> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0"> ${res.join('')} </svg> `) } } }
然后在vite.config中使用
vite.config
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { svgLoader } from './plugins/svgLoader'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue(), svgLoader('./src/assets/icon/svg')], resolve: { alias: { '@': 'src' } } })
在webpack中,为了提高首屏加载的速度或者是打包速度,包体大小会选择将部分比较重的第三方库抽离出来,通过cdn的方式外部导入。
module.exports = { configureWebpack: { externals: { vue: 'Vue', 'vue-router': 'VueRouter', 'element-ui': 'ELEMENT', }, }, }
配置后webpack会在打包阶段剔除这些包,并根据上述配置做一个映射,至于这一步的理由是因为从外部导入的是commonjs规范,会在全局变量上暴露一个名称,vue的话是Vue,element-ui对应的是ELEMENT。 换句话说,设置externals后,原代码里书写的import,from会被改写成从全局变量上获取。 上面也说过,vite是面向现代浏览器原生的es module功能,也就是说import from并不会被改写,那么想要做到第三方库的抽离就很简单了,以vue为例,只需要做到以下两点
vue
Vue
element-ui
ELEMENT
export default defineConfig(({ command }) => { const config = command === 'serve' ? {} : { resolve: { alias: { 'vue': 'https://unpkg.com/vue@3.1.5/dist/vue.runtime.esm-browser.prod.js' } } }; return { plugins: [vue(), vueJsx()], ...config, } })
和别名的写法一致。
import {defineComponent as e, createVNode as t, ref as n, resolveComponent as l, openBlock as s, createBlock as r, createApp as a} from "https://unpkg.com/vue@3.1.5/dist/vue.runtime.esm-browser.prod.js";
打包后会直接替换掉原来的vue。 看上去很简单,但是实际上这种做法对于有依赖关系的第三方库是行不通的。 如果你想抽离vue-router,会得到这样一个报错
vue-router
Uncaught TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".
从字面上很容易理解,导入的应该是一个路径,而不是简单的一个模块名。 涉及到vue的有两个地方,一个是项目本身,另一个就是刚刚引入的vue-router。
import { getCurrentInstance, inject, onUnmounted, onDeactivated, onActivated, computed, unref, defineComponent, reactive, watchEffect, h, provide, ref, watch, shallowRef, nextTick } from 'vue';
很明显,vue-router并没有对vue做处理。 [ESM browser module distribution depends on unsupported import](https://github.com/vuejs/vue-router-next/issues/694) 同样的问题在vuex中也是存在的,因为4.x的版本依赖了vue,采用了import { xxx } from 'vue'的方案导入,而这种方法是不符合esm规范的。 简单的说,现阶段没办法在vite上对vue-router@next和vuex@next进行第三方抽离。 总结起来有如下几点原因
[ESM browser module distribution depends on unsupported import](https://github.com/vuejs/vue-router-next/issues/694)
import { xxx } from 'vue'
vue-router@next
vuex@next
The text was updated successfully, but these errors were encountered:
No branches or pull requests
目前最大的感受就是一个字,快!
相较于webpack,以rollup为基础的vite,基于浏览器的模块化无论是冷启动还是打包都是异常的快速。
之前大大小小也在三四个项目上使用过vite,体验下来还有局限性的。
1.兼容性
这个问题主要是因为vite的核心是
es module
,简单的说就是依赖浏览器的模块化功能(import和export)这里可以简单的看一下目前各浏览器对module的支持程度,很明显对于IE等传统浏览器打包后的代码是无法运行的。但是这个问题目前可以通过官方插件@vitejs/plugin-legacy来支持。
2.社区生态不够成熟
相较于webpack成熟的社区生态,大部分问题都可以找到对应的库来解决,但是在这一点上,刚刚起步的vite很明显是做不到的。现阶段,如果想要在项目上使用,需要做好造轮子的心里准备。
举一个简单的例子,原先webpack的项目针对svg的加载,都是通过svg-sprite-loader来实现的。
而vite很明显不能这样实现svg的动态加载。
然后在
vite.config
中使用3.对于第三方库的外部导入不太友好
在webpack中,为了提高首屏加载的速度或者是打包速度,包体大小会选择将部分比较重的第三方库抽离出来,通过cdn的方式外部导入。
配置后webpack会在打包阶段剔除这些包,并根据上述配置做一个映射,至于这一步的理由是因为从外部导入的是commonjs规范,会在全局变量上暴露一个名称,
vue
的话是Vue
,element-ui
对应的是ELEMENT
。换句话说,设置externals后,原代码里书写的import,from会被改写成从全局变量上获取。
上面也说过,vite是面向现代浏览器原生的
es module
功能,也就是说import from并不会被改写,那么想要做到第三方库的抽离就很简单了,以vue为例,只需要做到以下两点和别名的写法一致。
打包后会直接替换掉原来的
vue
。看上去很简单,但是实际上这种做法对于有依赖关系的第三方库是行不通的。
如果你想抽离
vue-router
,会得到这样一个报错从字面上很容易理解,导入的应该是一个路径,而不是简单的一个模块名。
涉及到
vue
的有两个地方,一个是项目本身,另一个就是刚刚引入的vue-router
。很明显,vue-router并没有对vue做处理。
[ESM browser module distribution depends on unsupported import](https://github.com/vuejs/vue-router-next/issues/694)
同样的问题在vuex中也是存在的,因为4.x的版本依赖了vue,采用了
import { xxx } from 'vue'
的方案导入,而这种方法是不符合esm规范的。简单的说,现阶段没办法在vite上对
vue-router@next
和vuex@next
进行第三方抽离。总结起来有如下几点原因
vue-router@next
和vuex@next
虽然有esm的包,但是因为采用import { xxx } from 'vue'
,不符合esm规范,导致无法通过cdn引入。综上所述,vite未来可期。
The text was updated successfully, but these errors were encountered: