转转极速前进 發表於 2026-1-28 14:49:00

甲方嫌弃,项目首页加载太慢

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<div>
<div>
<blockquote>
<p>有一天,甲方打开一个后台管理的项目,说有点卡,不太满意,项目经理叫我优化,重新打包一下。</p>
<p>从输入地址 到 展示 首屏,最佳时间在 3秒内,否则,甲方挂脸,咱就有可能有被裁的风险,understand?</p>
</blockquote>
<blockquote>
<p>废话不多说,先来看一下怎么个优化法吧。</p>
</blockquote>
<h2 data-id="heading-0">优化</h2>
<h3 data-id="heading-1">✅ cdn</h3>
<h4 data-id="heading-2">分析</h4>
<p>用Webpack Bundle Analyzer分析依赖,安装webpack-bundle-analyzer打包分析插件:</p>
</div>
<br>
<blockquote>
<div>
<p># NPM<br>npm install --save-dev webpack-bundle-analyzer</p>
</div>
</blockquote>
</div>
<blockquote>
<p># Yarn<br>yarn add -D webpack-bundle-analyzer</p>
</blockquote>
<p>反正都是装,看着来。</p>
<p>配一下:</p>
<p>// vue.config.js 文件里。(没有就要新建一下)</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
plugins: [
    new BundleAnalyzerPlugin()
]
}</pre>
</div>
<h4 data-id="heading-3">打包</h4>
<p>执行打包命令并查看分析</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">npm run build --report</pre>
</div>
<p>打包结束后,会在项目根目录下生成dist文件。自动跳到<code>127.0.0.1:8888</code>(没有跳的话,手动打开dist文件夹下的report.html),这个网址就是<code>打包分析报告</code>。</p>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202601/2149129-20260128144110940-730682366.png" alt="ScreenShot_2026-01-28_144100_449" loading="lazy"></p>
<div>
<div>
<p>占得比较大的块,就是Element UI组件库和echarts库占的空间比相对较大。</p>
<p>这就要考虑,第一,要按需,要啥再用啥,不要一股脑啥都装。按需安装,按需加载。</p>
<p>第二,考虑单独引入这些组件库的<code>cdn</code>,这样速度也会咔咔提升。</p>
<p>详细讲一下怎么搞<code>cdn</code>。</p>
<p>按需大家都知道,要啥再引入啥,再装啥。</p>
<p>比如<code>element-ui</code>,我要<code>uninstall</code>掉,然后呢,去引入cdn,不要装库了,用cdn。</p>
<p>去<code>package.json</code>里面看<code>element-ui</code>装了啥版本,然后看完之后,就<code>npm uninstall element-ui</code>卸载掉。</p>
<p>去cdn库里面去找<code>https://www.staticfile.org/</code>,(首先先说一下,要找免费的开放的那种,因为一般有的公司没有自家的cdn,没有自家的桶,有的话,直接把js文件地址拖上去,然后得到一个地址,这样也安全,也方便,但没有的话另说)。</p>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202601/2149129-20260128144412747-809514276.png" alt="ScreenShot_2026-01-28_144408_738" loading="lazy"></p>
<blockquote>
<p>&nbsp;</p>
<p>样式库: https://cdn.staticfile.org/element-ui/2.15.12/theme-chalk/index.min.css <br>组件库:https://cdn.staticfile.org/element-ui/2.15.12/index.min.js</p>
</blockquote>
然后去<code>public/index.html</code>入口文件中,去加入这个东西,像咱以前写原生一样引入就好,body里面引入js,head里面引入css。:<br>
</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;head&gt;
&lt;link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.15.12/theme-chalk/index.min.css"&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;script src="https://cdn.staticfile.org/element-ui/2.15.12/index.min.js"&gt;&lt;/script&gt;
&lt;/body&gt;</pre>
</div>
<p>所以这样子,就引入好了。接着在<code>main.js</code>里面,把之前<code>import</code>的所有<code>element</code>的样式删掉。</p>
<p>接着,<code>vue.config.js</code>的<code>configureWebpack</code>加个<code>externals</code>字段:</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
plugins: [
    new BundleAnalyzerPlugin()
],
externals: {
    'element-ui': 'ELEMENT' // key 是之前install下下来的包名,element-ui。value是全局变量名(ELEMENT)
}
}</pre>
</div>
<div>
<div>
<p><strong>externals</strong>: Webpack 的 <code>externals</code> 配置用于声明某些依赖应该从外部获取,而不是打包到最终的 bundle 中。这样可以减小打包体积,前提是这些依赖已经在运行环境中存在。</p>
<p><strong><code>'element-ui': 'ELEMENT'</code> 的含义</strong></p>
<ul>
<li>当你的代码中 <code>import 'element-ui'</code> 时,Webpack 不会打包 <code>element-ui</code>,而是会从全局变量 <code>ELEMENT</code> 中获取它。</li>
<li><code>ELEMENT</code> 是 <code>element-ui</code> 库通过 <code>&lt;script&gt;</code> 标签引入时,在全局(<code>window</code>)中暴露的变量名。<br>
例如,如果你在 HTML 中这样引入:</li>
</ul>
</div>
</div>
<blockquote>
<p>&lt;script src="https://unpkg.com/element-ui/lib/index.js"&gt;&lt;/script&gt;</p>
</blockquote>
<div>
<div>
<ul>
<li>那么 <code>element-ui</code> 会挂载到 <code>window.ELEMENT</code> 上。</li>
</ul>
<p><strong>为什么这样配置?</strong></p>
<ul>
<li>通常是为了通过 CDN 引入 <code>element-ui</code>(而不是打包它),从而优化构建速度和体积。</li>
<li>你需要确保在 HTML 中通过 <code>&lt;script&gt;</code> 提前加载了 <code>element-ui</code>,否则运行时 <code>ELEMENT</code> 会是 <code>undefined</code>。</li>
</ul>
</div>

</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;!-- HTML 中通过 CDN 引入 element-ui --&gt;
&lt;script src="https://unpkg.com/element-ui/lib/index.js"&gt;&lt;/script&gt;</pre>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// webpack.config.js
module.exports = {
externals: {
    'element-ui': 'ELEMENT' // 告诉 Webpack:import 'element-ui' 时,返回全局的 ELEMENT
}
};</pre>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// 你的代码中依然可以正常 import(但实际用的是全局变量)
import ElementUI from 'element-ui';
// 相当于:const ElementUI = window.ELEMENT;</pre>
</div>
<div>
<div>
<p><strong>注意事项:</strong></p>
<ul>
<li>确保全局变量名(<code>ELEMENT</code>)和 <code>element-ui</code> 的 CDN 版本一致。不同版本的库可能有不同的全局变量名。</li>
<li>如果使用模块化打包(如 npm + Webpack 全量打包),则不需要配置 <code>externals</code>。</li>
</ul>
<hr>
<p>这里有的伙伴就说,我咋知道是<code>ELEMENT</code>,而不是<code>element</code>呢。</p>
<p>这里是这么找的:</p>
<p>直接在浏览器控制台检查 在 HTML 中通过 CDN 引入该库:</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;script src="https://cdn.staticfile.org/element-ui/2.15.12/index.min.js"&gt;&lt;/script&gt;</pre>
</div>
打开浏览器开发者工具(F12),在 Console 中输入:<br>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">console.log(window);</pre>
</div>
<p>然后查找可能的全局变量名(如 ELEMENT、ElementUI 等)。</p>
<h4 data-id="heading-4">cdn配置之后,重新分析</h4>
<blockquote>
<p>npm run build --report</p>
</blockquote>
<p>重新用<code>cdn</code>的去分析,</p>
<p>那么就很舒服了,也因此,这个就是cdn优化的方法。</p>
<h3 data-id="heading-5">✅ nginx gzip压缩</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">server {
      listen       8103;
      server_name************;
                # 开启gzip
          gzip on;
          # 进行压缩的文件类型。
                   gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
          # 是否在http header中添加Vary: Accept-Encoding,建议开启
          gzip_vary on;
}</pre>
</div>
<div>
<div>
<h3 data-id="heading-6">✅vue gzip压</h3>
<p>安包:<code>npm i compression-webpack-plugin@1.1.12 --save-dev </code></p>
<p>注意版本匹配问题。</p>
<p>vue配置,这段配置是 Webpack 构建中关于 <strong>Gzip 压缩</strong> 的设置,位于 <code>config/index.js</code> 文件中。:</p>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">//文件路径config --&gt; index.js
build: {
productionGzip: true, // 启用生产环境的 Gzip 压缩
productionGzipExtensions: ['js', 'css'], // 需要压缩的文件类型
}</pre>
</div>
<div>
<div>
<p><strong><code>productionGzip: true</code></strong></p>
<ul>
<li>作用:开启 Gzip 压缩,减少静态资源(JS、CSS)的体积,提升页面加载速度。</li>
<li>要求:需要安装 <code>compression-webpack-plugin</code>(如注释所述)。</li>
</ul>
</div>
</div>
<blockquote>
<p>npm install --save-dev compression-webpack-plugin</p>
</blockquote>
<div>
<div><ol>
<li>
<p><strong><code>productionGzipExtensions: ['js', 'css']</code></strong></p>
<ul>
<li>指定需要压缩的文件扩展名(默认压缩 JS 和 CSS 文件)。</li>
</ul>
</li>
</ol>
<p><strong>为什么需要 Gzip?</strong></p>
<ul>
<li><strong>优化性能</strong>:Gzip 压缩后的资源体积可减少 60%~70%,显著降低网络传输时间。</li>
<li><strong>服务器支持</strong>:大多数现代服务器(如 Nginx、Netlify)会自动对静态资源进行 Gzip 压缩,但本地构建时提前生成 <code>.gz</code> 文件可以避免服务器实时压缩的开销。</li>
</ul>
<h3 data-id="heading-7">✅ 按需加载路由</h3>
<p>路由级代码分割(动态导入)</p>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// 原写法
import About from './views/About.vue'

// 优化后写法
const About = () =&gt; import(/* webpackChunkName: "about" */ './views/About.vue')</pre>
</div>
<ul>
<li>首页只加载核心代码(home路由)</li>
<li>about模块会在用户点击about路由时才加载</li>
<li>显著减少首屏加载资源体积</li>
</ul>
<h3 data-id="heading-8">✅ 合理配置 prefetch策略</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// vue.config.js
module.exports = {
chainWebpack: config =&gt; {
    // 移除prefetch插件
    config.plugins.delete('prefetch')
   
    // 或者更精细控制
    config.plugin('prefetch').tap(options =&gt; {
      options.fileBlacklist = options.fileBlacklist || []
      options.fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
      return options
    })
}
}</pre>
</div>
<div>
<div>
<ul>
<li><strong>禁用prefetch</strong>:减少不必要的带宽消耗,但可能增加后续路由切换等待时间</li>
<li><strong>启用prefetch</strong>:利用浏览器空闲时间预加载,提升用户体验但可能浪费带宽</li>
<li><strong>折中方案</strong>:只对关键路由或高概率访问的路由启用prefetch</li>
</ul>
<h3 data-id="heading-9">✅ splitChunks 将node_modules中的依赖单独打包</h3>
<p><strong>拆分vendor</strong>:将node_modules中的依赖单独打包</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
   vendors: {
   name: 'chunk-vendors',
   test: /[\\/]node_modules[\\/]/,
   priority: -10,
   chunks: 'initial'
   }
}
})</pre>
</div>
<h3 data-id="heading-10">✅ 按需引入 lodash</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">import debounce from 'lodash/debounce'</pre>
</div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19543607
頁: [1]
查看完整版本: 甲方嫌弃,项目首页加载太慢