vite+vue3+ts搭建项目八(打包性能优化三:使用CDN)

news2025/1/26 15:36:13

vite+vue3+ts搭建项目八(打包性能优化三:使用CDN)

本文目录

    • vite+vue3+ts搭建项目八(打包性能优化三:使用CDN)
      • 使用vite-plugin-cdn-import
        • 下载npm包
        • 在vite.config.ts中通过importToCDN引入
        • CDN参数获取方式
        • 可用的CDN网址
        • 打包并运行
        • 报错整理
      • 使用rollup-plugin-external-globals(推荐)
        • 下载npm包
        • 在vite.config.ts中引入
        • 手动在打包后的index添加CDN
        • 自动添加CDN
        • element-plus相关问题

使用vite-plugin-cdn-import

下载npm包

官方github:https://github.com/MMF-FE/vite-plugin-cdn-import

npm install vite-plugin-cdn-import --save-dev

开发环境使用本地的npm包,cdn是打包时候才生效

在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';

// 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/vue@3.2.45/dist/vue.global.js`,
          
        },
        {
          name: 'vue-demi',
          var: 'VueDemi',
          path: `https://unpkg.com/vue-demi@0.13.11`,
        },
        {
          name: 'vue-router',
          var: 'VueRouter',
          path: `https://unpkg.com/vue-router@4.1.6`,
        },
        {
          name: 'element-plus',
          var: 'ElementPlus',
          path: 'https://unpkg.com/element-plus@2.3.3/dist/index.full.js',
          // css: 'https://unpkg.com/element-plus@2.3.3/dist/index.css'
        },
      ],
    }),
  ],
  // build: {
  //   rollupOptions: {
  //     external: ['vue', 'vue-demi', 'element-plus'],
  //   },
  // }
})

注意事项:网上很多教程,还需要在buildrollupOptions添加对应的external,如上注释所示,其实是不需要的,vite-plugin-cdn-import插件会自动帮我们完成这部分工作。

CDN参数获取方式

  • name:npm包的名称

    可以到https://www.jsdelivr.com进行查询,以element-plus为例

  • 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/vue-demi@0.13.11`,
    },
    
  • css:对应位置,参考上图element-plus
    需要注意的是,css可以使用本地的,使用本地的就不要添加css,使用远程cdn的就需要在打包前注释本地的,否则会出现样式重叠。

可用的CDN网址

namepordUrl
jsdelivrhttps://cdn.jsdelivr.net/npm/vue@3.2.47/dist/vue.global.min.js(例子)
unpkg//unpkg.com/{name}@{version}/{path}
cdnjs//cdnjs.cloudflare.com/ajax/libs/{name}/{version}/{path}

打包并运行

  • 打包后dist/index.html中自动添加了cdn链接

  • 打包后放到nginx中运行,查看对应依赖的加载地址

  • 打包后查看包体积
    例如element-plus,已经被排除在外了

报错整理

  • 报错 TypeError: importToCDN is not a function
  • 解决方法,修改import引入方式
    官方issues:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/22
    // 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')

    可以看到代码里用到了vue
  • 解决:将vue也通过cdn引入即可

  • 报错Uncaught ReferenceError: Vue is not defined

    vue-router或某些组件需要依赖vue
  • 解决:将vue也通过cdn引入即可

  • 报错 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-importunplugin-vue-componentsunplugin-auto-import不兼容
    参考:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/13#issuecomment-1226897835
    使用importToCDN时,通过下面两个插件的组件不生效,需要在每个组件单独写import
    import AutoImport from "unplugin-auto-import/vite"
    import Components from 'unplugin-vue-components/vite';
    
  • 原因
    之所以使用 AutoImport 后就会有问题,是因为 unplugin-auto-import 的 enforce 为 post ,会最后才执行,导致通过 AutoImport 的注入的代码没有被此插件转换
  • 解决方法
    目前只能暂时不同时使用这两组插件,所以如果使用自动引入插件,这个插件不是最佳答案

直接按照下面这张方法是不行的,在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/vue@3.2.45/dist/vue.global.js`,
          },
          ...
        ],
      }),
      enforce: 'post',
      apply: 'build',
    },
  ],
  // build: {
  //   outDir: 'dist', // 指定输出路径
  //   // minify: 'terser', // 混淆器,terser 构建后文件体积更小,'terser' | 'esbuild' ,默认为esbuild
  //   rollupOptions: {
  //     external: ['vue', 'vue-demi', 'element-plus'],
  //   },
  // }
})

使用rollup-plugin-external-globals(推荐)

为了解决上面的问题,externalGlobals是可以用上面的方法延迟加载的
参考1:https://github.com/ttk-cli/vue3-template/tree/test/cdn1
参考2:https://free_pan.gitee.io/freepan-blog

下载npm包

npm install -D rollup-plugin-external-globals

在vite.config.ts中引入

  1. 允许设置延迟加载
  2. rollupOptions需要设置external
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),
    },
  }
})

手动在打包后的index添加CDN

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue + TS</title>
    <script src="https://unpkg.com/vue@3.2.45/dist/vue.global.js"></script>
    <script src="https://unpkg.com/vue-demi@0.13.11"></script>
    <script src="https://unpkg.com/vue-router@4.1.6"></script>
    <script src="https://unpkg.com/element-plus@2.3.3/dist/index.full.js"></script>
    <script type="module" crossorigin src="/assets/index-c24c670c.js"></script>
    <link rel="stylesheet" href="/assets/index-f757e912.css">
  </head>
  <body>
    <div id="app"></div>
    
  </body>
</html>

自动添加CDN

需要用到vite-plugin-html插件
github官方:https://github.com/vbenjs/vite-plugin-html
参考:https://segmentfault.com/q/1010000041958028

  • 安装
npm i vite-plugin-html -D
  • 在vite.config.ts中引入(完整配置文件内容)
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/vue@3.2.45/dist/vue.global.js',
    'https://unpkg.com/vue-demi@0.13.11',
    'https://unpkg.com/vue-router@4.1.6',
    'https://unpkg.com/element-plus@2.3.3/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

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vite + Vue + TS</title>
  <!-- 使用CDN的CSS文件 -->
  <% for (const i of cdnCss) { %>
  <link href="<%= i %>" rel="stylesheet" />
  <% } %>
  <!-- 使用CDN的JS文件 -->
  <% for (const i of cdnJs) { %>
  <script src="<%= i %>" defer></script>
  <% } %>
</head>

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>

环境变量:https://www.cnblogs.com/yayuya/p/17035869.html

  • 打包后的结果

这样就不需要手动引入了,但是需要添加一个新的npm包,实际项目中可以自行选择是否添加

element-plus相关问题

使用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需要从远程地址读取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/413545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【事务】本地事务和分布式事务的区别

整理下事务相关的知识点&#xff1a; 文章目录一、事务MySQL事务事务的实现事务的ACID特性事务的隔离级别二、本地事务三、分布式事务认识分布式事务CAP理论BASE理论一、事务 先复习下数据库中学到的事务&#xff1a; MySQL事务 一个事务即一个完整的业务逻辑&#xff0c;如…

计算机组成原理——第三章存储系统(下)

提示&#xff1a;年年岁岁花相似&#xff0c;岁岁年年人不同 文章目录3.4.1 磁盘存储器3.4.2 固态硬盘SSD3.5.1 Cache的基本概念和原理3.5.2 Cache和主存的映射方式3.5.3 Cache替换算法3.5.4 Cache写策略3.6.1 页式存储3.6.2 虚拟存储器3.4.1 磁盘存储器 我们在磁性盘面上涂磁…

【hello Linux】Linux下 gitee 的使用

目录 1. 安装 git 2. gitee 的使用 2.1 注册 gitee 账号 2.2 创建项目&#xff1a;也就是仓库 2.3 下载项目到本地 3. 上传gitee三步走 3.1 三板斧第一招&#xff1a;git add 3.2 三板斧第二招&#xff1a;git commit 3.3 三板斧第三招&#xff1a;git push Linux&#x1f337…

【JavaEE】Spring项目的创建与使用

目录 创建Spring项目 创建Maven项目 引入依赖 使用镜像下载 下载依赖 添加启动类 使用Spring项目 创建Spring配置文件 存储Bean 取出并使用Bean(通过ApplicationContext接口) 通过id 通过class 通过classid(推荐) 取出并使用Bean(通过BeanFactory接口) Applicat…

从零入门激光SLAM(六)——ROS常用工具箱

大家好呀&#xff0c;我是一个SLAM方向的在读博士&#xff0c;深知SLAM学习过程一路走来的坎坷&#xff0c;也十分感谢各位大佬的优质文章和源码。随着知识的越来越多&#xff0c;越来越细&#xff0c;我准备整理一个自己的激光SLAM学习笔记专栏&#xff0c;从0带大家快速上手激…

【react 全家桶】组合组件

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录09 【组合组件】1.包含关系2.特例关系问题…

P3369 【模板】普通平衡树(FHQ Treap树构建和解析)

题目描述 您需要写一种数据结构&#xff08;可参考题目标题&#xff09;&#xff0c;来维护一些数&#xff0c;其中需要提供以下操作&#xff1a; 插入 x 数删除 x 数(若有多个相同的数&#xff0c;应只删除一个)查询 x 数的排名(排名定义为比当前数小的数的个数 1 )查询排名…

【Kafka-Kerberos下执行shell命令】Kafka在Kerberos环境下如何操作shell命令

【Kafka-Kerberos下执行shell命令】Kafka在Kerberos环境下如何操作shell命令1&#xff09;jaas.conf2&#xff09;client.properties3&#xff09;执行命令当大数据集群部署了 Kerberos 认证操作之后&#xff0c;在服务器上操作 kafka shell 命令就会出现认证相关的异常&#x…

【hello Linux】Linux开发工具

目录 1. vim&#xff1a;文本编辑器 1.1 各种模式的切换 补充&#xff1a;ctrl r命令 1.2 命令模式的操作 1.3 插入模式的操作 1.4 底行模式的操作 1.5 配置vim环境 1.6 配置亲属关系 2. gcc/g&#xff1a;编译器 2.1 预处理&#xff1a; 2.2 编译&#xff1a; 2.3 汇编&#x…

Gsum: A General Framework for Guided Neural Abstractive Summarization 论文笔记

Gsum: A General Framework for Guided Neural Abstractive Summarization 论文笔记 Year: 2021 Venue: NAACL Institution: CMU Code: https://github.com/neulab/guided_summarization Overview 这篇文章力求解决的问题是如何控制文本摘要生成&#xff0c;尤其注重可信度方…

floyed 4.9

今天是周末,也就不为难自己了,学习了一下floyed算法(确实简单哈哈),这个算法也是最短路的一种 在一副图中,a到b的距离可能不是直接的ab边最短,这时候就要用到floyed的思想了,可能是a到c到b比直接a到b最短.所以我们要枚举一边才可以知道a到b的最短的路线 这就是floyed的大概 …

7年测试,从功能测试到测试开发,我总算证明了自己

我感觉我是一个比较有发言权的人吧&#xff0c;我在测试行业爬模滚打7年&#xff0c;从点点点的功能测试到现在成为测试开发工程师&#xff0c;工资也翻了几倍&#xff1b; 个人觉得&#xff0c;测试的前景并不差&#xff0c;只要自己肯努力&#xff1b;我刚出来的时候是在鹅厂…

FL Studio21中文版D编曲数字音乐工作软件

随着现在人们的生活水平不断提高&#xff0c;我们的精神生活也越来越丰富&#xff0c;对于现在的年轻人来说&#xff0c;DJ舞曲是一个较受欢迎的领域&#xff0c;有许多年轻人对DJ这个职业感兴趣&#xff0c;想要深入了解DJ编曲这份工作&#xff0c;那么今天我们就来说一说DJ编…

聊聊ChatGPT无法取代的7个工作

ChatGPT——全世界都在谈论的非常流行的人工智能工具。自从 2022 年 11 月 30 日推出以来&#xff0c;ChatGPT 就被证明是执行复杂任务并简化它们的一体式工具。无论是通过 UPenn 的沃顿商学院 MBA 考试&#xff0c;撰写常春藤盟校入学论文&#xff0c;还是完成简单的任务&…

Django自带的Admin后台中如何获取当前登录用户

需求背景 在使用Django快速开发一个IT 电脑、显示器资产管理小系统的时候&#xff0c;遇到一个问题是&#xff0c;当变更资产设备&#xff08;新增、修改、删除&#xff09;的时候&#xff0c;能记录是谁在什么时间进行的变更。 确认的是肯定是登录状态&#xff0c;但是在使用…

算法学习|动态规划 LeetCode 647. 回文子串、516.最长回文子序列

动态规划一、回文子串思路实现代码二、最长回文子序列思路实现代码&#xff08;希望自己能总结出做过的动态规划题&#xff01;要开始回顾之前刷过的题了&#xff09; 一、回文子串 给定一个字符串&#xff0c;你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或…

回收站数据恢复的方法技巧

​最近有网友反映将一些不经常使用的文件放入回收站后忘记了&#xff0c;清空回收站后想要再次使用文件却怎么都还原不了&#xff0c;想利用回收站数据恢复软件经恢复&#xff0c;咨询有哪些回收站数据恢复软件推荐&#xff0c;下面就给大家推荐回收站数据恢复软件使用方法。 …

数据库开发重点存档

2023春数据库开发复习 T1 视图可以用的几个场景&#xff1f; 不同表字段聚合、信息重组&#xff1a;当某个查询涉及多表连接、次数频繁时&#xff0c;可以创建视图隐藏底层表的复杂性&#xff0c;简化查询。 控制权限&#xff1a;根据不同用户的权限&#xff0c;可以建立不同…

星巴克创始人第三次重出江湖

星巴克创始人第三次出山&#xff0c;与中国有关 中国咖啡连锁竞争白热化 星巴克诞生于1985年&#xff0c;爷爷级的公司 趣讲大白话&#xff1a;百年老店不容易 【趣讲信息科技135期】 **************************** 将心注入 星巴克创始人自传 创始人的激情、执行力、团队建设很…

HttpRunner3.x 源码解析(5)-runner.py

首先看下生成的pytest文件 from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCaseclass TestCaseLogin(HttpRunner):config (Config("登录成功").variables(**{"password": "tester", "expect_foo2": "co…