![cover](https://img-blog.csdnimg.cn/4d66457bc25e4ae68af20e0eeb5507b7.png)
详解vue 配置 cdn 加载依赖的方法
前言生产环境中,将项目依赖的一些第三方包替换成通过 cdn 方式外部加载,而不是打包到 vender,对于提升应用的加载、响应速度很有意义,下面我们一步步的实现这点CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络
前言
生产环境中,将项目依赖的一些第三方包替换成通过 cdn 方式外部加载,而不是打包到 vender,对于提升应用的加载、响应速度很有意义,下面我们一步步的实现这点
CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率
1. 查看打包后的资源情况
首先使用 build 命令打包,看看在使用 cdn 加载外部资源之前,应用的速度及包的体积大小情况
推荐使用 vue ui 命令启动一个 GUI 的窗口,通过此窗口进行打包,可以看到更多信息
vue ui
此命令必须在 vue 项目所在的目录下运行(最好通过管理员身份打开 powshell),如我的 vue 项目在 d:\code\vue 目录下,就将此目录作为 powshell 的工作目录,然后再运行 vue ui
命令,否则就会出现目录无法选择,或者一致加载中等问题
打开工具后,执行 build 命令对我当前的一个项目进行生产环境打包(你针对自己的项目打包即可)
我们都知道
- 开发者编写的组件等代码会打包到 app文件中(名字会随机,比如上面是 app5e6d08ab.js)
- 通过 import 引入的第三方依赖包,会打包到 vender 文件中
同时还会生成相关的css 和字体文件
上图左侧列出了各个文件的大小,右侧列出了第三方依赖包占用的体积
通过这个图可以查看生成文件的体积,并找到哪个依赖包占用体积较大,以及哪些文件占用体积较大,从而进行优化
从右侧可以看出,如果将部分依赖包不要打包到 vener 文件中,而是使用 cdn 节点的方式,应该可以减少文件的体积,从而提升页面响应速度
这也是使用 CDN 节点的原因
2.打包入口文件
原来的打包入口文件为 main.js
无论是开发环境的打包,还是生产环境的打包,都通过此文件
现在,我们新建两个文件
- main-prod:生产环境打包,通过 cdn 的方式引入第三方依赖包
- main-dev:开发环境打包,将第三方依赖包打包到 vender 文件中
- main.js 可以删除
两个文件的代码暂时一样,都是 main.js 的复制
开发环境不重视响应速度吗?
开发环境(development) 和生产环境(production) 的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间
说白了就是开发环境下打包到 vender 中是有利于开发的(而且这些包都在开发者本地,加载速度可以忽略),生产环境下使用 cdn 等方式可以减少 bundle 体积
3.修改webpack配置方式
现在设置不同的打包命令走不同的入口文件,这需要修改 webpack 的打包设置
默认情况下 vue/cli 隐藏了 webpack 配置选项,所以在目录中,找不到熟悉的 webpack.config.js 文件,目的是让开发人员从繁杂的配置中解脱出来,集中精力到业务逻辑和功能开发商
直接在 vue.config.js 中修改即可,其会覆盖脚手架项目中默认的打包设置
上面链接的文档说明了所有的可选的配置项
从文档中得知,在 vue.config.js 中修改 webpack 配置的方式可以选择
- chainWebpack:通过链式编程方式修改
- configureWebpack:通过操作对象、合并对象的方式修改
两种方式都是用来修改配置的,只不过实现方式不一样,如果是简单的配置,推荐使用 chainWebpack 方式,如果复杂的设置,推荐使用 configureWebpack
4.使用 chainWebpack 修改配置
下面代码根据不同的环境调用不同的入口文件
module.exports = defineConfig({
transpileDependencies: true, // 生产环境打包不输出 map 文件
// 通过chainWebpack 配置开发环境和生产环境的打包设置
chainWebpack: config => {
// 生产环境配置
config.when(process.env.NODE_ENV === 'production', config => {
{
config.entry('app').clear().add('./src/main-prod.js')
}
})
// 开发环境设置
config.when(process.env.NODE_ENV === 'development', config => {
{
config.entry('app').clear().add('./src/main-dev.js')
}
})
}
})
配置完成后,分别运行 npm run dev
和 npm run build
命令测试配置是否成功,只要都可以运行,就证明配置没有问题
问题:为什么运行不同的命令,就会使用不同的打包入口文件,换句话说:为什么运行不同的命令,process.env.NODE_ENV
的值就会不同?
5,配置 externals
现在开始配置生产环境下使用 CDN,大概有这么几个步骤
- 通过 externals 选项配置打包时例外,这些包不会打包到 vender 中,而是从外部加载
- 在 index.html 中通过 script 加载这些包
- 如果某些依赖还需要引入 css,也可以通过 link 引入 css 文件,从而删除那些 `import ‘xx.css’ 代码,从而进一步减少包的体积
通过 config.set 方法设置 webpack 的 externals 选项,
外部扩展(Externals) | webpack 中文文档 (docschina.org)
vue.config.js 中配置
config.set('externals', {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
lodash: '_',
moment: 'moment',
nprogress: 'NProgress',
'element-ui': 'ELEMENT'
})
externalsd的值是一个对象,当程序打包时,回到 vue.config.js 中搜寻 externals
中的所有配置项,对象中的依赖都不会打包到 vender 中,而是通过外部资源加载
语法如下
- 键:我们要引入的包的名称,如
import XXX from 'pageckage'
中的package。 - 值:包在 windows 全局变量中的名称。如果你有过 vue 组件的开发经验,应该知道,组件如果想除了支持 npm 方式引入外,还支持使用 script 标签方式引入,就必须将包名称注册到 window 全局变量中,这样开发者才可以使用(全局变量的名字不是随意起的)
- 某些依赖并没有配置进来,主要是有些包比较小众,不容易在网上找到现成的 cdn 资源,可以考虑将其放在公司自己的 cdn 服务器上或者更换
每个依赖包全局变量的名字到底是什么?一种方式是去其官网查看,如 vue
6.引用外部资源
上面说过,externals
中的依赖会使用外部资源,也就是通过 script 方式引入
所以,我们就在 index.html 中引入这些链接,这些链接对应的资源加载后,就会创建 externals
中的值,并将其加载到 window 全局变量中
<link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.15.6/theme-chalk/index.min.css">
<link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css">
<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/3.5.1/vue-router.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.26.1/axios.min.js"></script>
<script src="https://cdn.staticfile.org/lodash.js/4.17.21/lodash.min.js"></script>
<script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
<script src="https://cdn.staticfile.org/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.staticfile.org/element-ui/2.15.6/index.min.js"></script>
注意:
- 上面使用的七牛云的cdn节点,尽量使用与 package.json 中记录的版本相同的资源
- 七牛云上寻找对应版本的资源时,其并没有严格按照版本的数字关系排序(可能是根据版本发布顺序),请耐心寻找
- 某些依赖包还需要 css,以前我们是通过 import 导入,现在也是用 cdn 节点方式引入(注意要删除原来 import 引入的代码),如进度条组件的css
附上完整代码
7.element-ui 的特殊性
element-ui 与 moment、axios 这些简单的包不太一样
我们原来采用的是按需引入,但是通过 下面链接引入的是elementui的完整库
<script src="https://cdn.staticfile.org/element-ui/2.15.6/index.min.js"></script>
其会暴漏一个全局变量 ELEMENT,所以,我们除了在 externals 中配置之外
还要再入口文件中,取消原来按需引入的代码,转而使用完整引入的语法
如果打包没有问题,下面操作忽略即可
另外,还要删除 babel.config.js
中按需引入需要的插件配置,否则其仍会将 element-ui 打包(同时仍然会下载外部资源)
8.重新打包对比
重新打包,发现很多文件的体积都缩小了
响应速度分析
资源占用情况分析
运行打包之后的代码,发现如下资源都是从外部下载的,已经不再 vender 文件中了
9. 两种环境下的 index.html
现在生产环境的打包已经没问题了
但此时开发模式下打包后,再运行程序,提示不能重复定义 $router 属性
原因在于:*通常是因为在项目中安装了vue-router的依赖并且用Vue.use()使用了vue-router,还在index.html页面引入了vue-router.js文件
将 index.html 中引入 vue-router 的代码移除即可
但是生产环境的打包又需要 vue-router 等外部资源
所以,最终解决方案,就是像办法实现如下效果
- 生产环境下,index.html 保留这些资源引用代码
- 开发环境下,index.html 不加载这些资源引用代码
很显然,需要在 index.html 中加入一个判断条件,而判断条件依赖的变量,可以在 vue.config.js 中定义
依赖于一个 html 插件,在 webpack 打包过程中,向 args 数组中添加元素,然后在 index.html 中读取整个元素的值,并进行判断
<link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.15.6/theme-chalk/index.min.css">
<link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css">
<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/3.5.1/vue-router.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.26.1/axios.min.js"></script>
<script src="https://cdn.staticfile.org/lodash.js/4.17.21/lodash.min.js"></script>
<script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
<script src="https://cdn.staticfile.org/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.staticfile.org/element-ui/2.15.6/index.min.js"></script>
<% } %>
开发模式下打包,发现 index.html 中没有那些 script 和 link 标签了,程序也能正常运行了
生产环境下打包,发现 index.html 中那些 script 和 link 标签又回来了
更多推荐
所有评论(0)