官方github:https://github.com/MMF-FE/vite-plugin-cdn-import
npm install vite-plugin-cdn-import --save-dev
开发环境使用本地的npm包,cdn是打包时候才生效
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
import { visualizer } from 'rollup-plugin-visualizer';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
importToCDN({
// prodUrl: 'https://cdn.jsdelivr.net/npm/{name}@{version}/{path}',
modules: [
{
name: 'vue',
var: 'Vue',
path: `https://unpkg.com/[email protected]/dist/vue.global.js`,
},
{
name: 'vue-demi',
var: 'VueDemi',
path: `https://unpkg.com/[email protected]`,
},
{
name: 'vue-router',
var: 'VueRouter',
path: `https://unpkg.com/[email protected]`,
},
{
name: 'element-plus',
var: 'ElementPlus',
path: 'https://unpkg.com/[email protected]/dist/index.full.js',
// css: 'https://unpkg.com/[email protected]/dist/index.css'
},
],
}),
],
// build: {
// rollupOptions: {
// external: ['vue', 'vue-demi', 'element-plus'],
// },
// }
})
注意事项:网上很多教程,还需要在build
的rollupOptions
添加对应的external
,如上注释所示,其实是不需要的,vite-plugin-cdn-import
插件会自动帮我们完成这部分工作。
name:npm包的名称
var:组件(main.ts)引用的名称
比如ElementPlus
import ElementPlus from 'element-plus'
app.use(ElementPlus)
path:cdn网站存储对应的js地址
输入对应名称,会自动跳转到对应的js文件,复制粘贴,需要修改版本,和自己项目的package.json版本一致
允许只写到版本,后面会自动补齐
{
name: 'vue-demi',
var: 'VueDemi',
path: `https://unpkg.com/[email protected]`,
},
css:对应位置,参考上图element-plus
需要注意的是,css可以使用本地的,使用本地的就不要添加css,使用远程cdn的就需要在打包前注释本地的,否则会出现样式重叠。
name | pordUrl |
---|---|
jsdelivr | https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.min.js(例子) |
unpkg | //unpkg.com/{name}@{version}/{path} |
cdnjs | //cdnjs.cloudflare.com/ajax/libs/{name}/{version}/{path} |
TypeError: importToCDN is not a function
// import importToCDN from "vite-plugin-cdn-import";
import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
Uncaught TypeError: Cannot read properties of undefined (reading 'createElementVNode')
报错 Uncaught TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".
参考1:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/13
参考2:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/32
参考3:https://blog.csdn.net/qq_51634332/article/details/126325740
解决:importToCDN时在引入vue后添加vue-demi,已在vite.config.ts中给出,其他插件在vue-demi之后(顺序很重要)
vite-plugin-cdn-import
与unplugin-vue-components
和unplugin-auto-import
不兼容import AutoImport from "unplugin-auto-import/vite"
import Components from 'unplugin-vue-components/vite';
直接按照下面这张方法是不行的,在vite.config.ts文件中,为importToCDN添加...扩展符
,让它在其他所有插件之后再加载
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
import { visualizer } from 'rollup-plugin-visualizer';
import AutoImport from "unplugin-auto-import/vite"
import Components from 'unplugin-vue-components/vite';
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router'],
dts: "src/auto-import.d.ts",
}),
Components({
//默认存放位置
//dts: "src/components.d.ts",
}),
{
...importToCDN({
// prodUrl: 'https://cdn.jsdelivr.net/npm/{name}@{version}/{path}',
modules: [
{
name: 'vue',
var: 'Vue',
path: `https://unpkg.com/[email protected]/dist/vue.global.js`,
},
...
],
}),
enforce: 'post',
apply: 'build',
},
],
// build: {
// outDir: 'dist', // 指定输出路径
// // minify: 'terser', // 混淆器,terser 构建后文件体积更小,'terser' | 'esbuild' ,默认为esbuild
// rollupOptions: {
// external: ['vue', 'vue-demi', 'element-plus'],
// },
// }
})
为了解决上面的问题,externalGlobals是可以用上面的方法延迟加载的
参考1:https://github.com/ttk-cli/vue3-template/tree/test/cdn1
参考2:https://free_pan.gitee.io/freepan-blog
npm install -D rollup-plugin-external-globals
import externalGlobals from 'rollup-plugin-external-globals'
const externalGlobalsObj = {
vue: 'Vue',
'vue-demi': 'VueDemi',
'vue-router': 'VueRouter',
'element-plus': 'ElementPlus',
}
export default defineConfig({
plugins: [
vue(),
{
...externalGlobals(externalGlobalsObj),
enforce: 'post',
apply: 'build',
},
],
build: {
outDir: 'dist', // 指定输出路径
rollupOptions: {
external: Object.keys(externalGlobalsObj),
},
}
})
Vite + Vue + TS
需要用到vite-plugin-html
插件
github官方:https://github.com/vbenjs/vite-plugin-html
参考:https://segmentfault.com/q/1010000041958028
npm i vite-plugin-html -D
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
import { visualizer } from 'rollup-plugin-visualizer';
// 自动导入vue中hook reactive ref等
import AutoImport from "unplugin-auto-import/vite"
// 自动导入ui-组件 比如说ant-design-vue element-plus等
import Components from 'unplugin-vue-components/vite';
import externalGlobals from 'rollup-plugin-external-globals'
import { createHtmlPlugin } from 'vite-plugin-html'
const cdn = {
css: [],
js: [
'https://unpkg.com/[email protected]/dist/vue.global.js',
'https://unpkg.com/[email protected]',
'https://unpkg.com/[email protected]',
'https://unpkg.com/[email protected]/dist/index.full.js',
],
}
const externalGlobalsObj = {
vue: 'Vue',
'vue-demi': 'VueDemi',
'vue-router': 'VueRouter',
// pinia: 'Pinia',
'element-plus': 'ElementPlus',
}
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
const isProduction = mode === 'production';
return {
plugins: [
vue(),
AutoImport({
//安装两行后,在组件中不用再导入ref,reactive等
imports: ['vue', 'vue-router'],
dts: "src/auto-import.d.ts",
//element
}),
Components({
//element
//默认存放位置
//dts: "src/components.d.ts",
}),
visualizer({
open: true, //注意这里要设置为true,否则无效
gzipSize: true, //从源代码中收集 gzip 大小并将其显示在图表中
brotliSize: true, //从源代码中收集 brotli 大小并将其显示在图表中
emitFile: true, //在打包完的dist,否则在项目目录下
filename: "stats.html", //分析图生成的文件名
}),
createHtmlPlugin({
inject: {
data: {
cdnCss: isProduction ? cdn.css : [],
cdnJs: isProduction ? cdn.js : [],
},
},
}),
{
...externalGlobals(externalGlobalsObj),
enforce: 'post',
apply: 'build',
},
],
build: {
outDir: 'dist', // 指定输出路径
// minify: 'terser', // 混淆器,terser 构建后文件体积更小,'terser' | 'esbuild' ,默认为esbuild
rollupOptions: {
external: Object.keys(externalGlobalsObj),
},
}
}
})
在 index.html 中增加 EJS 标签
需要注意的是:这个index.html不是打包后的,是项目的入口index.html
Vite + Vue + TS
<% for (const i of cdnCss) { %>
<% } %>
<% for (const i of cdnJs) { %>
<% } %>
环境变量:https://www.cnblogs.com/yayuya/p/17035869.html
这样就不需要手动引入了,但是需要添加一个新的npm包,实际项目中可以自行选择是否添加
使用cdn引入需要全局引入,不要使用AutoImport的按需引入,否则最后生成的包仍然会有本地的element-plus.js
按需引入和CDN只能选择其一进行打包优化
使用CDN则不使用resolvers: [ElementPlusResolver()]
,在main.ts全局引入element-plus即可
AutoImport({
//安装两行后,在组件中不用再导入ref,reactive等
imports: ['vue', 'vue-router'],
dts: "src/auto-import.d.ts",
//element
// resolvers: [ElementPlusResolver()],
}),
Components({
//element
//默认存放位置
//dts: "src/components.d.ts",
// resolvers: [ElementPlusResolver()],
}),
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
app.use(ElementPlus)
使用CDN未必会加快速度,只能减小打包体积,因为对应js和css需要从远程地址读取