一.概述
- 使用CDN的好处
- 缓解服务器的压力,将首屏加载时的请求分摊给其它的服务器
- 优化打包后verdor.js过大问题
- 加快首屏加载速度
- 加快打包速度
- 尤其是Vue3新的Tree-Shaking技术,只打包需加载的模块module,搭配CDN后如虎添翼!
二.CDN网站分享
根据需要自行切换相关CDN
依赖引用并非全部可用,有的js会不兼容, 自行尝试通过可用后在进行引用操作!
-
国内
BootCdn网站 https://www.bootcdn.cn/
七牛云 http://staticfile.org/ -
国外
unpkg网站 https://unpkg.com
cdnjs网站 https://cdnjs.com/
jsdelivr网站 https://www.jsdelivr.com/
vite-plugin-cdn-import:cdn的引入插件
npm i vite-plugin-cdn-import
or
pnpm i vite-plugin-cdn-import
vite.config.js
// import { autoComplete, Plugin as importToCDN } from 'vite-plugin-cdn-import'// 引入cdn
import { Plugin as importToCDN } from 'vite-plugin-cdn-import'
plugins: [
vue(),
eslint({
// 配置项
// include: ['src/**/*.js', 'src/**/*.vue', 'src/**/*.jsx', 'src/**/*.ts'],
// exclude: ['./node_modules/**'],
cache: false // 禁用eslint缓存
}),
// 自动导入 element-plus
// AutoImport({
// resolvers: [ElementPlusResolver()]
// }),
// Components({
// resolvers: [ElementPlusResolver()]
// }),
// build生成分析工具
visualizer({
emitFile: true, // 打包后的分析文件会出现在打包好的文件包下
filename: 'state.html', // 分析图生成的文件名
open: true // 如果存在本地服务端口,将在打包后自动展示
// sourcemap: true// 使用sourcemap计算大小
}),
// 第三方库CDN引入
importToCDN({
prodUrl: 'https://unpkg.com/{name}@{path}',
modules: [
// autoComplete('vue'),
// autoComplete('axios'),
// {
// name: 'vue',
// var: 'Vue',
// path: 'https://unpkg.com/vue@3.3.4'
// },
{
name: 'vue',
var: 'Vue',
path: '3.3.4'
},
{
name: 'vue-demi', // vue版本选好 不然会报错
var: 'VueDemi',
path: '0.14.5'
},
{
name: 'vue-router',
var: 'VueRouter',
path: '4.2.2'
},
{
name: 'element-plus',
var: 'ElementPlus',
path: '2.3.6',
css: '2.3.6/dist/index.css'
},
{
name: '@element-plus/icons-vue',
var: 'ElementPlusIconsVue', // 根据main.js中定义的来
path: '2.1.0'
},
{
name: 'pinia',
var: 'Pinia',
path: '2.1.3'
}
]
})
],
使用cdn 引入 element-plus 一定也要用cdn 引入 vue、vue-demi 并且引入顺序不能出错,
-
如果不引入vue-demi,可以理解为vue和vue-demi 是互相引用的关系
-
注意使用vite-plugin-cdn-import插件 不能按需引入element、直接在main.ts中使用全局引入的方式,打包后会自动按照cdn引入
main.ts
// import { App, createApp } from 'vue'
import { createApp } from 'vue'
// import "./style.css";
import AppData from './App.vue'
// routes
import router from './router/index'
import { createPinia } from 'pinia'
// 样式重置
import 'normalize.css'
import '@/assets/styles/index.scss'
import ElementPlus from 'element-plus'
// import * as icons from '@element-plus/icons'
// import 'element-plus/dist/index.css'//cdn 自动载入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const pinia = createPinia()
const app = createApp(AppData)
app.use(router)
app.use(ElementPlus)
app.use(pinia)
app.mount('#app')
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
最终打包展示
完整代码
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
// import AutoImport from 'unplugin-auto-import/vite'
// import Components from 'unplugin-vue-components/vite'
// import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// import postCssPxToRem from 'postcss-pxtorem'
import eslint from 'vite-plugin-eslint' // 新增
import { resolve } from 'path'
// import path from 'path' // 配置文件路径相关时,需要用到此项 由于node不支持ts,需要安装依赖以便支持 需执行如下命令 npm install @types/node --save-dev
import { visualizer } from 'rollup-plugin-visualizer'// 分析优化
// import { autoComplete, Plugin as importToCDN } from 'vite-plugin-cdn-import'// 引入cdn
import { Plugin as importToCDN } from 'vite-plugin-cdn-import'
// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
const env = loadEnv(mode, process.cwd()) // 获取.env文件里定义的环境变量
console.log('command', command, 'mode', mode, 'env', env)
// ****打包文件名称****
let fileName = 'dist'
// 兼容性,以防打包崩溃
fileName = env.VITE_APP_NAME
return {
base: env.VITE_ENV === 'production' ? './' : './', // 静态路径访问地址
build: {
outDir: fileName,
assetsDir: 'static', // 指定生成静态资源的存放路径
emptyOutDir: true, // 清除输出目录
// 设置为 false 可以禁用最小化混淆,或是用来指定使用哪种混淆器。默认为 Esbuild,它比 terser 快 20-40 倍,压缩率只差 1%-2%
// npm add -D terser
minify: 'terser', // boolean | 'terser' | 'esbuild',混淆:terser,false是否压缩代码
sourcemap: true, // 构建后是否生成 source map 文件
target: 'esnext',
terserOptions: {
compress: {
// drop_console: true, // 生产环境去掉控制台 console
// drop_debugger: true, // 生产环境去掉控制台 debugger 默认就是true
// dead_code: true // 删除无法访问的代码 默认就是true
}
},
// 文件超过500Kb解决办法
chunkSizeWarningLimit: 1024 * 50,
rollupOptions: {
output: {
// 最小化拆分包
manualChunks (id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
},
// dist下面的assets文件下,里面既有js、css等等。因此,可以将不同的文件放在不同的文件下,这样比较好。
// 拆分js到模块文件夹
chunkFileNames: (chunkInfo) => {
const facadeModuleId = chunkInfo.facadeModuleId
? chunkInfo.facadeModuleId.split('/')
: []
const fileName1 = facadeModuleId[facadeModuleId.length - 2] || '[name]'
return `js/${fileName1}/[name].[hash].js`
},
// 用于从入口点创建的块的打包输出格式[name]表示文件名,[hash]表示该文件内容hash值
entryFileNames: 'js/[name].[hash].js',
// 用于输出静态资源的命名,[ext]表示文件扩展名
assetFileNames: '[ext]/[name].[hash:4].[ext]'
}
}
},
plugins: [
vue(),
eslint({
// 配置项
// include: ['src/**/*.js', 'src/**/*.vue', 'src/**/*.jsx', 'src/**/*.ts'],
// exclude: ['./node_modules/**'],
cache: false // 禁用eslint缓存
}),
// 自动导入 element-plus
// AutoImport({
// resolvers: [ElementPlusResolver()]
// }),
// Components({
// resolvers: [ElementPlusResolver()]
// }),
// build生成分析工具
visualizer({
emitFile: true, // 打包后的分析文件会出现在打包好的文件包下
filename: 'state.html', // 分析图生成的文件名
open: true // 如果存在本地服务端口,将在打包后自动展示
// sourcemap: true// 使用sourcemap计算大小
}),
// 第三方库CDN引入
importToCDN({
prodUrl: 'https://unpkg.com/{name}@{path}',
modules: [
// autoComplete('vue'),
// autoComplete('axios'),
// {
// name: 'vue',
// var: 'Vue',
// path: 'https://unpkg.com/vue@3.3.4'
// },
{
name: 'vue',
var: 'Vue',
path: '3.3.4'
},
{
name: 'vue-demi', // vue版本选好 不然会报错
var: 'VueDemi',
path: '0.14.5'
},
{
name: 'vue-router',
var: 'VueRouter',
path: '4.2.2'
},
{
name: 'element-plus',
var: 'ElementPlus',
path: '2.3.6',
css: '2.3.6/dist/index.css'
},
{
name: '@element-plus/icons-vue',
var: 'ElementPlusIconsVue', // 根据main.js中定义的来
path: '2.1.0'
},
{
name: 'pinia',
var: 'Pinia',
path: '2.1.3'
}
]
})
],
resolve: {
// 配置路径别名
alias: {
'@': resolve(__dirname, './src')
// '@': path.resolve(__dirname, 'src') // 用 @ 符号替换 src 文件路径
}
},
css: {
// 此代码为适配移动端px2rem
// postcss: {
// plugins: [
// postCssPxToRem({
// rootValue: 37.5, // 1rem的大小(控制1rem的大小 点位:px)
// propList: ["*"], // 需要转换的属性,这里选择全部都进行转换
// }),
// ],
// },
},
server: {
host: '0.0.0.0',
port: 3001, // 端口号
open: false, // 是否自动打开浏览器
// 跨域代理
proxy: {
// 字符串简写写法
'/foo': 'http://localhost:4567',
// 选项写法
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
// // 正则表达式写法
// '^/fallback/.*': {
// target: 'http://jsonplaceholder.typicode.com',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/fallback/, '')
// },
// // 使用 proxy 实例
// '/api': {
// target: 'http://jsonplaceholder.typicode.com',
// changeOrigin: true,
// configure: (proxy, options) => {
// // proxy 是 'http-proxy' 的实例
// }
// }
}
}
}
})