<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          2022 年最新前端 Vue 項(xiàng)目重構(gòu)總結(jié)

          共 3598字,需瀏覽 8分鐘

           ·

          2022-02-12 15:16

          大廠技術(shù)??高級(jí)前端??Node進(jìn)階

          點(diǎn)擊上方?程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群

          本文主要內(nèi)容

          1. 對(duì)于老舊的項(xiàng)目,升級(jí)webpack的時(shí)我的操作步驟。
          2. 基于項(xiàng)目的產(chǎn)品定位和業(yè)務(wù)發(fā)展走勢(shì),在重構(gòu)時(shí)我可以從哪方面入手和思考。

          本文在項(xiàng)目迭代,優(yōu)化中一直修改,所以用時(shí)一年。如果能給您帶來幫助,希望各位大佬可以動(dòng)動(dòng)小手給我點(diǎn)贊????,您的點(diǎn)贊是我寫文的最好的肯定!謝謝??

          背景及解決方法

          因?yàn)楣镜漠a(chǎn)品是把同類型的業(yè)務(wù)軟件在不同電商平臺(tái)上架,所以新開的項(xiàng)目是把老代碼移植過來,刪改拼湊后上架。因此文件目錄零散,引入導(dǎo)出混亂,代碼冗余,風(fēng)格不夠統(tǒng)一規(guī)范。這些毛病導(dǎo)致代碼可讀性和維護(hù)性很低,且樣式?jīng)_突很多,奇怪的難復(fù)現(xiàn)的bug也很多。我就計(jì)劃在迭代填坑中,對(duì)項(xiàng)目進(jìn)行一次改造優(yōu)化。我的解決步驟如下:

          • 第一步:了解基本業(yè)務(wù)(三個(gè)月左右),值班時(shí)多詢問客戶建議,了解用戶的使用習(xí)慣和對(duì)我們軟件的風(fēng)格定位。對(duì)同類型的競(jìng)品(八個(gè)左右,我們軟件做的還可以)進(jìn)行了詳細(xì)的調(diào)研,分析我們產(chǎn)品的不足和優(yōu)勢(shì)。同時(shí)和產(chǎn)品積極溝通項(xiàng)目后期開發(fā)方向和計(jì)劃。我覺得項(xiàng)目在我接手的時(shí)候,功能目前只完成了計(jì)劃的20%,還有很高的完善空間。這個(gè)過程大概花費(fèi)了半年吧。
          • 第二步:基于項(xiàng)目目錄混亂,我先對(duì)項(xiàng)目的目錄根據(jù)功能模塊重新劃分,把router路由path對(duì)應(yīng)文件路徑,利于后期模塊查找。
          • 第三步:對(duì)基本資源對(duì)公共資源統(tǒng)一入口,這樣有利于后期資源的管理維護(hù),在代碼上也不用做重復(fù)引入的操作。例如css的公共css統(tǒng)一入口引入,公共變量通過loader可全局使用,不再手動(dòng)引入。對(duì)font采用動(dòng)態(tài)加載,刪除本地存儲(chǔ)的svg文件。
          • 第四步:因?yàn)轫?xiàng)目的webpack版本是2,且為全手寫,考慮到后期同事維護(hù)和我本人計(jì)劃性分步迭代升級(jí)的改造方式,我沒有采用vue-cli,也采用了全手配。具體升級(jí)步驟在下面也有書寫
          • 第五步:項(xiàng)目?jī)?nèi)部高復(fù)用邏輯封裝和內(nèi)部代碼邏輯優(yōu)化。因?yàn)槲覀冺?xiàng)目面對(duì)的是b端客戶,有很多數(shù)據(jù)的查詢,我就寫了一個(gè)具有列表的查詢,分頁(yè),搜索功能的model,配合vuex就很方便。

          項(xiàng)目webpack升級(jí)

          配置步驟

          先把入口文件main.js的所有代碼都注釋掉,在根目錄創(chuàng)建文件夾:webpack(打包腳本的文件夾),webpack文件夾下創(chuàng)建 webpack.common.js(webpack通用配置)、webpack.development.js(webpack開發(fā)環(huán)境下配置腳本)、webpack.product.js(webpack生產(chǎn)環(huán)境下配置腳本)三個(gè)文件。

          1. 在main.js引入一個(gè)最簡(jiǎn)單的.vue文件,只有template模版,配置vue-loader,使項(xiàng)目正常運(yùn)行。在script腳本處編寫命令行:
          {
          ????"dev":?"webpack-dev-server??./webpack/webpack.common.js?--mode='development'",????
          ????"build":?"webpack?--config?./webpack/webpack.common.js??--mode='production'"
          ??}
          復(fù)制代碼
          1. 在.vue文件中寫js代碼,配置 babel,使項(xiàng)目正常運(yùn)行。
          2. 在.vue文件中寫css、less代碼,配置 css和less,使項(xiàng)目正常運(yùn)行。
          3. 在.vue文件中引入圖片,字體等,配置 靜態(tài)資源,使項(xiàng)目正常運(yùn)行。
          4. 在app.vue文件內(nèi)只引入簡(jiǎn)單組件,再嘗試引入一個(gè)頁(yè)面,使項(xiàng)目正常運(yùn)行。此時(shí)項(xiàng)目的基礎(chǔ)配置完成
          5. 區(qū)分環(huán)境變量,分開打包并配置腳本命令并優(yōu)化打包腳本

          資源打包

          vue配置

          vue-loader: 允許你以一種名為單文件組件 \(SFCs\)[2]的格式撰寫 Vue 組件

          npm?i?-D?vue-loader
          復(fù)制代碼

          modules配置

          const?{?VueLoaderPlugin?}?=?require('vue-loader')

          {
          ????output:?{
          ????????path:?path.resolve(__dirname,?'../dist'),
          ????????filename:?'[name].[chunkhash].js',
          ????????chunkFilename:?'[name].[chunkhash].js',
          ????????publicPath:?'/'
          ????},
          ????plugins:?[
          ????????new?VueLoaderPlugin(),
          ????],
          ????module:?{
          ??????rules:?[
          ????????????{
          ????????????????test:?/\.vue$/,
          ????????????????use:?[
          ????????????????????{
          ????????????????????loader:?'cache-loader'
          ????????????????????},
          ????????????????????{
          ????????????????????loader:?'vue-loader',
          ????????????????????options:?{
          ????????????????????????transformAssetUrls:?{
          ????????????????????????video:?['src',?'poster'],
          ????????????????????????source:?'src',
          ????????????????????????img:?'src',
          ????????????????????????image:?['xlink:href',?'href'],
          ????????????????????????use:?['xlink:href',?'href']
          ????????????????????????},
          ????????????????????????cssSourceMap:?true,
          ????????????????????????hotReload:?true,
          ????????????????????????compilerOptions:?{
          ????????????????????????preserveWhitespace:?true
          ????????????????????????}
          ????????????????????}
          ????????????????????}
          ????????????????],
          ????????????????exclude:?/node_modules/
          ????????????},
          ????????]
          ????},
          }

          復(fù)制代碼

          驗(yàn)證:在終端輸入命令行npm run build無報(bào)錯(cuò),dist內(nèi)如下圖展示

          babel配置

          @babel/core: 把js 代碼分析成ast ,方便各個(gè)插件分析語(yǔ)法進(jìn)行相應(yīng)的處理
          @babel/cli: 是_babel_?提供的命令行工具,用于命令行下編譯源代碼
          babel-loader: 在Webpack打包的時(shí)候,用BabelES6的代碼轉(zhuǎn)換成ES5版本的,開啟緩存cacheDirectory:true,可以在node_modules/.cache內(nèi)看到緩存文件
          @babel/preset-env: 可以根據(jù)配置的目標(biāo)瀏覽器或者運(yùn)行環(huán)境來自動(dòng)將ES2015+的代碼轉(zhuǎn)換為es5,配置useBuiltIns:true可實(shí)現(xiàn)按需引入。配置corejs:3指定corejs的版本。
          core-js: 它是JavaScript標(biāo)準(zhǔn)庫(kù)的polyfill,盡可能的進(jìn)行模塊化,讓你能選擇你需要的功能。

          可參考文章:\# babel兼容性實(shí)現(xiàn)方案[3]

          npm?install?--save-dev?@babel/core?@babel/cli?@babel/preset-env?babel-loader?@babel/plugin-transform-runtime
          復(fù)制代碼

          .babelrc配置

          {
          ????"presets":?[
          ????????["@babel/preset-env",?{
          ????????????"useBuiltIns":?"usage",
          ????????????"corejs":?3,
          ????????????"targets":?{
          ??????????????"browsers":?[">?1%",?"last?2?versions",?"not?ie?<=?8"]
          ????????????}
          ??????????}]
          ????],
          ????"plugins":?[
          ??????"@babel/plugin-transform-runtime"
          ????]
          }
          復(fù)制代碼

          module配置

          {
          ????test:?/\.js$/,
          ????use:?[
          ??????{
          ????????loader:?'babel-loader',
          ????????options:?{
          ??????????presets:?['@babel/preset-env'],
          ??????????babelrc:?true,
          ??????????cacheDirectory:?true?//?啟用緩存
          ????????}
          ??????}
          ????],
          ????exclude:?/node_modules/
          }
          復(fù)制代碼

          "babel": "babel src/index.js \--out-dir dist" 命令來編譯 src/index.js測(cè)試文件
          npm run babel打包后的結(jié)果驗(yàn)證

          css

          vue-style-loader: 把js 代碼分析成ast ,方便各個(gè)插件分析語(yǔ)法進(jìn)行相應(yīng)的處理
          css-loader: 解析css文件中的@import和url語(yǔ)句,處理css-modules,并將結(jié)果作為一個(gè)js模塊返回
          postcss-loader: 將css3轉(zhuǎn)為低版本瀏覽器兼容寫法,及兼容未來版本的css寫法,加載對(duì)應(yīng)的插件
          autoprefixer:解析CSS文件并且添加瀏覽器前綴到CSS內(nèi)容里
          postcss:使用插件去轉(zhuǎn)換CSS的工具
          less-loader: 將less代碼轉(zhuǎn)譯為瀏覽器可以識(shí)別的CSS代碼
          style-resources-loader:導(dǎo)入css 預(yù)處理器的一些公共的樣式文件變量

          npm?install?--save-dev?vue-style-loader?css-loader?postcss-loader?autoprefixer?postcss?less-loader?style-resources-loader
          復(fù)制代碼

          module配置

          {
          ????????test:?/\.less$/,
          ????????use:?[
          ??????????'vue-style-loader',
          ??????????{
          ????????????loader:?'css-loader',
          ????????????options:?{
          ??????????????importLoaders:?3
          ????????????}
          ??????????},
          ??????????{
          ????????????loader:?'postcss-loader',
          ????????????options:?{
          ??????????????indent:?'postcss',
          ??????????????plugins:?(loader)?=>?[
          ????????????????require('autoprefixer')()?//?添加前綴
          ??????????????],
          ??????????????sourceMap:?false
          ????????????}
          ??????????},
          ??????????{
          ????????????loader:?'less-loader',
          ????????????options:?{
          ??????????????javascriptEnabled:?true,
          ??????????????sourceMap:?true
          ????????????}
          ??????????},
          ??????????{
          ????????????loader:?'style-resources-loader',
          ????????????options:?{
          ??????????????patterns:?[
          ????????????????path.resolve(__dirname,?'../src/assets/css/variables/*.less'),
          ??????????????],
          ??????????????injector:?(source,?resources)?=>?{
          ????????????????const?combineAll?=?type?=>?resources
          ??????????????????.filter(({?file?})?=>?file.includes(type))
          ??????????????????.map(({?content?})?=>?content)
          ??????????????????.join('')

          ????????????????return?combineAll('variables')?+?combineAll('mixins')?+?source
          ??????????????}
          ????????????}
          ??????????}
          ????????],
          ????????exclude:?/node_modules/
          ??????},
          復(fù)制代碼

          npm run build打包后的結(jié)果驗(yàn)證

          less

          style-resources-loader: 避免重復(fù)在每個(gè)樣式文件中@import導(dǎo)入,在各個(gè)css 文件中能夠直接使用 變量和公共的樣式
          在css配置的基礎(chǔ)上,最后面添加style-resources-loader,這樣就再也不用手動(dòng)引入css變量

          {
          ????????loader:?'style-resources-loader',
          ????????options:?{
          ??????????patterns:?[
          ????????????path.resolve(__dirname,?'../src/assets/css/variables/*.less')
          ??????????],
          ??????????injector:?(source,?resources)?=>?{
          ????????????const?combineAll?=?type?=>?resources
          ??????????????.filter(({?file?})?=>?file.includes(type))
          ??????????????.map(({?content?})?=>?content)
          ??????????????.join('')

          ????????????return?combineAll('variables')?+?combineAll('mixins')?+?source
          ??????????}
          }
          復(fù)制代碼

          npm run build打包后的結(jié)果驗(yàn)證

          MiniCssExtractPlugin: 提取JS中的CSS樣式,用 link 外部引入,減少JS文件的大小

          const?MiniCssExtractPlugin?=?require('mini-css-extract-plugin')

          {
          ????plugins:?[
          ????????new?MiniCssExtractPlugin({
          ??????????filename:?'[name].[contenthash].css',
          ??????????chunkFilename:?'[id].[contenthash].css',
          ??????????ignoreOrder:?true
          ????????}),
          ????]
          }
          復(fù)制代碼

          把上面的 vue-style-loader 替換為 MiniCssExtractPlugin.loader

          npm run build打包后的結(jié)果驗(yàn)證

          圖片&svg&音頻&font

          svg-sprite-loader: 把js 代碼分析成ast ,方便各個(gè)插件分析語(yǔ)法進(jìn)行相應(yīng)的處理
          url-loader: 解析css文件中的@import和url語(yǔ)句,處理css-modules,并將結(jié)果作為一個(gè)js模塊返回

          npm?install?--save-dev?svg-sprite-loader?url-loader
          復(fù)制代碼
          ?{
          ????????test:?/\.svg$/,
          ????????loader:?'svg-sprite-loader',
          ????????include:?[path.join(__dirname,?'..',?'src/assets/icon')],
          ????????options:?{
          ??????????symbolId:?'[name]',
          ??????????name:?path.posix.join('static',?'img/[name].[hash:7].[ext]')
          ????????}
          ??????},
          ??????{
          ????????test:?/\.(png|jpe?g|gif)(\?.*)?$/,
          ????????loader:?'url-loader',
          ????????exclude:?/node_modules/,
          ????????options:?{
          ??????????limit:?10000,
          ??????????name:?path.posix.join('static',?'img/[name].[hash:7].[ext]')
          ????????}
          ??????},
          ??????{
          ????????test:?/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
          ????????loader:?'url-loader',
          ????????exclude:?/node_modules/,
          ????????options:?{
          ??????????limit:?10000,
          ??????????name:?path.posix.join('static',?'media/[name].[hash:7].[ext]')
          ????????}
          ??????},
          ??????{
          ????????test:?/\.(woff|woff2?|eot|ttf|otf)(\?.*)?$/,
          ????????loader:?'url-loader',
          ????????options:?{
          ??????????limit:?10000,
          ??????????name:?path.posix.join('static',?'fonts/[name].[hash:7].[ext]')
          ????????}
          ??????}
          復(fù)制代碼

          公共部分webpack.common.js優(yōu)化

          1. externals 排除外部依賴打包到bundle中

          externals:?{
          ??'vue':?'Vue',
          }
          復(fù)制代碼

          npm run build打包后的結(jié)果驗(yàn)證:設(shè)置externals后,dist內(nèi)找不到vue.js的package包了。下圖為設(shè)置前的截圖

          2. resolve 縮小查找范圍 降低查找速度

          resolve:?{
          ????extensions:?['.js',?'.vue',?'.json'],
          ????alias:?{
          ??????'vue$':?'vue/dist/vue.esm.js',
          ??????'@':?path.join(__dirname,?'..',?'src'),
          ??????'@services':?path.join(__dirname,?'..',?'src/api/services.js'),
          ??????'@productsManagement':?path.join(__dirname,?'..',?'src/modules/productsManagement')
          ????}
          ??},
          復(fù)制代碼

          3. cache-loader 緩存

          cache-loader: 在一些性能開銷較大的 loader 之前添加 cache-loader,以便將結(jié)果緩存到磁盤里,此處寫在vue-loader的前面

          ?{
          ????test:?/\.vue$/,
          ????use:?[
          ??????{
          ????????loader:?'cache-loader'
          ??????},
          ??????{
          ????????loader:?'vue-loader'
          ??????}
          ????]
          ??},
          復(fù)制代碼

          npm run build打包后的結(jié)果驗(yàn)證:可以在node_modules下的.cache看到緩存的文件

          3. plugins

          1. DefinePlugin 變量替換
          2. WebpackBar 打包進(jìn)度展示
          3. FriendlyErrorsWebpackPlugin 配置終端輸出日志
          4. HtmlWebpackPlugin 動(dòng)態(tài)生成html
          5. LodashModuleReplacementPlugin 按需引入
          6. VueLoaderPlugin 熱重載
          7. HardSourceWebpackPlugin 緩存 webpack 內(nèi)部模塊
          8. thread-loader 多線程打包
          const?WebpackBar?=?require('webpackbar')
          const?FriendlyErrorsWebpackPlugin?=?require('friendly-errors-webpack-plugin')
          const?LodashModuleReplacementPlugin?=?require('lodash-webpack-plugin')
          const?HardSourceWebpackPlugin?=?require('hard-source-webpack-plugin')

          const?argv?=?require('yargs-parser')(process.argv.slice(-3))
          const?mode?=?argv.mode?||?'development'
          const?isDev?=?mode?===?'development'
          const?jsWorkerPool?=?{
          ??poolTimeout:?2000
          }


          plugins:?[
          ????new?webpack.DefinePlugin({
          ??????'process.env':?JSON.stringify(mode),
          ??????'process.env.BUILD_ENV':?JSON.stringify(mode)
          ????}),
          ????new?WebpackBar({
          ??????name:?isDev???'development'?:?'production',
          ??????color:?isDev???'#00953a'?:?'#f2a900'
          ????}),
          ????new?FriendlyErrorsWebpackPlugin(),
          ????new?LodashModuleReplacementPlugin(),
          ????new?VueLoaderPlugin(),
          ????new?HtmlWebpackPlugin({
          ??????filename:?'index.html',
          ??????template:?'index.html',
          ??????inject:?true,
          ??????minify:?{
          ????????removeComments:?true,
          ????????collapseWhitespace:?true,
          ????????removeAttributeQuotes:?true
          ??????}
          ????}),
          ????new?HardSourceWebpackPlugin({}),
          ],
          復(fù)制代碼

          HardSourceWebpackPlugin: 為模塊提供中間緩存,緩存默認(rèn)的存放路徑是:?node_modules/.cache/hard-source,首次構(gòu)建時(shí)間沒有太大變化,但是第二次開始,構(gòu)建時(shí)間大約可以節(jié)約 80%

          npm run build打包后,HardSourceWebpackPlugin的結(jié)果驗(yàn)證

          LodashModuleReplacementPlugin: 該插件將會(huì)移除你未用到的lodash特性 npm run build打包后,LodashModuleReplacementPlugin的結(jié)果驗(yàn)證

          thread-loader: 把這個(gè) loader 放置在其他 loader 之前, 放置在這個(gè) loader 之后的 loader 就會(huì)在一個(gè)單獨(dú)的 worker 池(worker pool)中運(yùn)行,加快打包速度。這里先不實(shí)驗(yàn),因?yàn)?thread-loader 適合在耗時(shí)的 loader 上使用,不然反而會(huì)減慢速度。

          4. optimization splitChunks& runtimeChunk(manifest)

          splitChunks: 提取被重復(fù)引入的文件,單獨(dú)生成一個(gè)或多個(gè)文件,這樣避免在多入口重復(fù)打包文件
          script-ext-html-webpack-plugin: 將 runtimeChunk 內(nèi)聯(lián)到我們的 index.html
          runtimeChunk: 作用是將包含chunks映射關(guān)系的list單獨(dú)從app.js里提取出來,因?yàn)槊恳粋€(gè)chunk的id基本都是基于內(nèi)容hash出來的,所以你每次改動(dòng)都會(huì)影響它,如果不把它提取出來的話,等于app.js每次都會(huì)改變,緩存就失效了

          const?ScriptExtHtmlWebpackPlugin?=?require('script-ext-html-webpack-plugin')

          output:?{
          ??????path:?path.resolve(__dirname,?'../dist'),
          ??????filename:?'[name].[chunkhash].js',
          ??????chunkFilename:?'[name].[chunkhash].js',
          ??????publicPath:?'/'
          },
          plugins:[
          ????new?ScriptExtHtmlWebpackPlugin({
          ??????inline:?/runtime\..*\.js$/
          ????}),
          ],
          optimization:?{
          ????runtimeChunk:?true,?//?構(gòu)建出runtime~xx文件
          ????splitChunks:?{
          ??????name:?true,?//?自動(dòng)處理文件名
          ??????chunks:?'all',
          ??????automaticNameDelimiter:?'-',
          ??????cacheGroups:?{
          ????????vendors:?{
          ??????????test:?/[\\/]node_modules[\\/]/,
          ??????????priority:?10,
          ??????????name:?'vendors',
          ??????????chunks:?'initial'
          ????????},
          ????????commons:?{
          ??????????name:?'commons',
          ??????????minChunks:?2,
          ??????????priority:?5,
          ??????????test:?path.join(__dirname,?'..',?'src/components'),
          ??????????reuseExistingChunk:?true
          ????????}
          ??????}
          ????}
          ??}
          復(fù)制代碼

          先在src下創(chuàng)建a.js、b.js文件,在main.js通過 動(dòng)態(tài)加載 import()引入,webpackChunkName為按需引入后打包的名稱。npm run build打包后,runtimeChunk的結(jié)果驗(yàn)證

          npm run build打包后,splitChunks的結(jié)果驗(yàn)證

          npm run build打包后,cript-ext-html-webpack-plugin的結(jié)果驗(yàn)證

          5. stats bundle 配置終端輸出日志

          stats: 后端打包腳本是通過docker部署,所以需要配置webpack輸出信息,不然info都是黑白的,看日志的時(shí)候比較費(fèi)勁

          stats:?{
          ????colors:?true,
          ????modules:?false,
          ????children:?false,
          ????chunks:?false,
          ????chunkModules:?false
          ??}
          復(fù)制代碼

          開發(fā)環(huán)境優(yōu)化

          1. devtool 調(diào)試方式

          webpack.common.js內(nèi)配置

          const?merge?=?require('webpack-merge')
          const?argv?=?require('yargs-parser')(process.argv.slice(-3))
          const?mode?=?argv.mode?||?'development'
          const?mergeConfig?=?require(`./webpack.${mode}.js`)
          const?common?=?merge(commonConfig,?mergeConfig)
          module.exports?=?common
          復(fù)制代碼
          devtool:?'cheap-module-eval-source-map',
          復(fù)制代碼

          2. devServer & HotModuleReplacementPlugin

          這個(gè)一般都會(huì),就不贅述了

          plugins:[?
          ????new?webpack.HotModuleReplacementPlugin()
          ],
          devServer:?{
          ????historyApiFallback:?true,
          ????overlay:?{
          ??????errors:?true
          ????},
          ????//?通知文件更改
          ????watchOptions:?{
          ??????poll:?true
          ????},
          ????open:?false,
          ????hot:?true,
          ????proxy:?{
          ??????'/api':?{
          ????????target:?'http://localhost:10080/',
          ????????changeOrigin:?true,
          ????????pathRewrite:?{
          ??????????'^/api':?'/api'
          ????????}
          ??????}
          ????},
          ????host:?'0.0.0.0',
          ????port:?8000
          },
          復(fù)制代碼

          生產(chǎn)環(huán)境優(yōu)化

          todo: 考慮說出每個(gè)插件的作用 zhuanlan.zhihu.com/p/102632472[4]

          1. plugins

          CleanWebpackPlugin: 刪除dist
          OptimizeCssAssetsPlugin: css優(yōu)化壓縮插件
          cssnano: 一個(gè)?PostCSS[5]?插件,可以添加到你的構(gòu)建流程中,用于確保最終生成的 用于生產(chǎn)環(huán)境的 CSS 樣式表文件盡可能的小。CompressionPlugin: 壓縮生成gzip

          const?{CleanWebpackPlugin}?=?require('clean-webpack-plugin')
          const?MiniCssExtractPlugin?=?require('mini-css-extract-plugin')
          const?OptimizeCssAssetsPlugin?=?require('optimize-css-assets-webpack-plugin')
          const?CompressionPlugin?=?require('compression-webpack-plugin')

          plugins:?[
          ????new?CleanWebpackPlugin(),
          ????new?OptimizeCssAssetsPlugin({
          ??????assetNameRegExp:?/\.less$/g,
          ??????cssProcessor:?require('cssnano'),
          ??????cssProcessorPluginOptions:?{
          ????????preset:?['default',?{
          ??????????discardComments:?{?removeAll:?true?},
          ??????????normalizeUnicode:?false,?//?建議false,否則在使用unicode-range的時(shí)候會(huì)產(chǎn)生亂碼
          ??????????safe:?true?//?避免?cssnano?重新計(jì)算?z-index
          ????????}]
          ??????},
          ??????canPrint:?true
          ????}),
          ????new?CompressionPlugin({
          ??????algorithm:?'gzip',?//?'brotliCompress'
          ??????test:?/\.js$|\.html$|\.css/,?//?+?$|\.svg$|\.png$|\.jpg
          ??????threshold:?10240,?//?對(duì)超過10k的數(shù)據(jù)壓縮
          ??????deleteOriginalAssets:?false?//?不刪除原文件
          ????})
          ??],
          ??optimization:?{
          ????moduleIds:?'size',
          ????minimizer:?[
          ??????//?這樣配置會(huì)存在只有css壓縮的問題,這時(shí)webpack4原本自己配置好的js壓縮會(huì)無效?,需要重新配置UglifyJsPlugin(用于壓縮js,webpack4內(nèi)置了)一下
          ??????//?https://www.jianshu.com/p/dd9afa5c4d0f
          ??????new?OptimizeCssAssetsPlugin({})
          ????]
          ??},
          復(fù)制代碼

          在后端項(xiàng)目ngix配置內(nèi)

          gzip?on;
          gzip_min_length?1k;
          gzip_buffers?4?16k;
          gzip_http_version?1.1;
          gzip_comp_level?5;
          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;
          gzip_disable?"MSIE?[1-6]\.";
          gzip_vary?on;
          復(fù)制代碼

          npm run build打包后, OptimizeCssAssetsPlugin的結(jié)果驗(yàn)證 npm run build打包后, CompressionPlugin 的結(jié)果驗(yàn)證

          2. optimization

          1. moduleIds 持久化緩存 如何看打包后的chunk效果[6]

          optimization.moduleIds: 'size'

          2. UglifyJsPlugin

          ?minimizer:?[
          ??new?UglifyJsPlugin({
          ????exclude:?/\.min\.js$/,
          ????parallel:?os.cpus().length,
          ????cache:?true,
          ????sourceMap:?true,
          ????uglifyOptions:?{
          ??????compress:?{
          ????????warnings:?false,
          ????????drop_console:?true,
          ????????collapse_vars:?true,
          ????????reduce_vars:?true
          ??????},
          ??????output:?{
          ????????beautify:?false,
          ????????comments:?false
          ??????}
          ????}
          ??})
          ]
          復(fù)制代碼
          image.png

          項(xiàng)目?jī)?yōu)化之動(dòng)態(tài)加載

          對(duì)于項(xiàng)目里比較大的組建都可以使用 es6的 import() 動(dòng)態(tài)加載,添加webpackChunkName魔法注釋。

          1. 不常用的modal、draw等彈出框,可以對(duì)這些組件異步延遲加載,從首屏加載的代碼剝離
          2. 路由懶加載
          {
          ??path:?'/productsManagement/allProducts',
          ??name:?'AllProducts',
          ??component:?()?=>?import(
          ????/*?webpackChunkName:?`AllProducts`?*/
          ????/*?webpackMode:?"lazy"?*/
          ????'@productsManagement/allProducts/DyProductList'),
          ??meta:?{
          ????keepAlive:?true,
          ????requiresAuth:?true
          ??}
          },
          復(fù)制代碼

          成果對(duì)比

          打包速度

          優(yōu)化前,生產(chǎn)環(huán)境第一次打包時(shí)間:49038ms 優(yōu)化前,生產(chǎn)環(huán)境第二次打包時(shí)間:70113ms 優(yōu)化后,生產(chǎn)環(huán)境第一次打包時(shí)間:47663ms 優(yōu)化后,生產(chǎn)環(huán)境第二次打包時(shí)間:13738ms, 快了70%

          打包后資源大小展示

          以下是整理文件,分包后打包未使用gzip后的生產(chǎn)包,使用gzip會(huì)有更小的包加載

          靜態(tài)資源整理

          icon

          我寫了一個(gè)icon組建vue-midou-icon[7] 。此組建支持iconfont平臺(tái)對(duì)接,不需手動(dòng)下載icon。使用方式如下:

          //?注冊(cè)
          import?MdUi?from?'vue-midou-icon'
          //?在main.js內(nèi)導(dǎo)入
          import?"vue-midou-icon/lib/midou.css"?

          const?IconFont?=?MdUi.createFromIconfontCN({
          ??scriptUrl:[
          ????'your-iconfont-symbbol-url'
          ??],
          ??//?name可以不寫?默認(rèn)為?md-icon
          ??name:?'your-iconfont-component-name',
          })
          Vue.use(IconFont)


          //組建使用
          "iconType"?class="className">
          </your-iconfont-component-name>
          復(fù)制代碼

          images

          1. 圖片需要壓縮,壓縮地址[8]。可以根據(jù)圖片的實(shí)際大小,多次壓縮。
          2. 當(dāng)圖片比較小。就可以考慮放在本地。在webpack的配置中進(jìn)行打包處理
          3. 如果圖片是gif動(dòng)態(tài)圖。可以考慮讓ui逐幀截取后再做圖片預(yù)加載。如何做預(yù)加載可以參考 頁(yè)面圖片預(yù)加載與懶加載策略[9]
          4. 長(zhǎng)列表圖片使用element—ui的image,支持懶加載

          fonts

          我們的項(xiàng)目里有在線編輯圖片,所以要加載很多ui字體。每個(gè)字體包在轉(zhuǎn)換之前有17M。通過壓縮轉(zhuǎn)換字體,把otf轉(zhuǎn)換成woff。就變成了5kb,不過字體會(huì)稍微有點(diǎn)點(diǎn)改變。點(diǎn)擊進(jìn)入字體壓縮地址[10]

          css

          1. css變量規(guī)范,使用style-resources-loader[11]全局注入
          2. 公共css分開整理,統(tǒng)一入口引入
          3. 業(yè)務(wù)css與組建統(tǒng)一文件夾

          代碼優(yōu)化

          目錄整理與模塊劃分

          原來的目錄結(jié)構(gòu)的公共組件和頁(yè)面業(yè)務(wù)組件沒有分開,所以組件越來越多,且有路由直接加載components里的組件的現(xiàn)象。目錄結(jié)構(gòu)混亂。沒有模塊劃分的概念。

          公共邏輯抽離 createLoading、modelExtengs、listModel、baseModel

          1. modelExtend[12] 類目dva的 dva-model-extend,點(diǎn)擊名稱可查看代碼
          2. createBaseModel[13] 列表請(qǐng)求的篩選和查詢封裝,點(diǎn)擊名稱可查看代碼
          3. createLoadingPlugin[14] 類目dva的 action的loading中間件,點(diǎn)擊名稱可查看代碼

          下面是代碼使用demo

          store.js中的注冊(cè)

          import?Vue?from?'vue'
          import?Vuex?from?'vuex'
          import?createLoadingPlugin?from?'./plugins/createLoadingPlugin'
          import?{setBaseModelConfig}?from?'@commonModels/createBaseModel.js'
          import?productManagement?from?'./modules/productManagement'
          import?customerSetting?from?'./modules/customerSetting'

          setBaseModelConfig({
          ??//?列表獲取
          ??getList:?(response)?=>?{
          ????let?tableData
          ????tableData?=?response.items
          ????return?{
          ??????tableData,
          ??????total:?response.total
          ????}
          ??},
          ??//?參數(shù)格式化?
          ??formatParmas:?(parmas)?=>?{
          ????//?合并分頁(yè)和篩選的數(shù)據(jù)
          ????return?{
          ??????...parmas.pagination,
          ??????...parmas.filters
          ????}
          ??},
          ??//?錯(cuò)誤警告
          ??handleError:?(err,?self)?=>?{
          ????self._vm.$message({
          ??????message:?`${err}`,
          ??????type:?'error'
          ????})
          ??},
          ??//?分頁(yè)配置
          ??pagination:?{
          ????page_size:?10,
          ????page_index:?1
          ??}
          })

          Vue.use(Vuex)
          const?modules?=?{
          ??...productManagement,
          ??...customerSetting
          }

          export?default?new?Vuex.Store({
          ??modules,
          ??plugins:?[createLoadingPlugin({Vue})]
          })
          復(fù)制代碼

          [15]vuex文件中的掛載

          import?createBaseModel?from?'@commonModels/createBaseModel.js'
          import?modelExtend?from?'@commonModels/modelExtend.js'
          import?services?from?'@services'

          const?model?=?modelExtend(
          ??createBaseModel({
          ????fetch:?services.userCapturePage
          ??}),
          ??{
          ????namespaced:?true,
          ????state:?()?=>?({
          ????}),
          ????actions:?{
          ??????async?fetch?({commit,?state,?dispatch},?payload)?{
          ????????await?dispatch('query',?{?...payload?})
          ??????}
          ????},
          ????getters:?{

          ????}
          ??})
          export?default?model
          復(fù)制代碼

          [16]在**.vue**文件中的調(diào)用





          復(fù)制代碼

          利用require.context自動(dòng)注冊(cè)

          const?requireDirectives?=?require.context(
          ??'@/dirname',
          ??false,
          ??/([\w\W]*)\.(vue|js)$/
          )

          export?const?registerDirectives?=?()?=>
          ??requireDirectives.keys().forEach(fileName?=>?{
          ????const?directiveConfig?=?requireDirectives(fileName)
          ????const?directiveName?=?fileName.split('/').pop().replace(/\.\w+$/,?'')
          ????Vue.directive(
          ??????directiveName,
          ??????directiveConfig.default?||?directiveConfig
          ????)
          ??})
          復(fù)制代碼

          求點(diǎn)贊

          邊開發(fā)邊做的,個(gè)人感覺還有很多不夠完善的地方。希望大家看到了可以不吝賜教,感激不盡。。如果覺得不錯(cuò),求點(diǎn)贊,謝謝各位大佬!!!!??


          關(guān)于本文

          來源:kris和小土豆

          https://juejin.cn/post/7050400511828164644

          Node 社群



          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。



          如果你覺得這篇內(nèi)容對(duì)你有幫助,我想請(qǐng)你幫我2個(gè)小忙:

          1. 點(diǎn)個(gè)「在看」,讓更多人也能看到這篇文章
          2. 訂閱官方博客?www.inode.club?讓我們一起成長(zhǎng)

          點(diǎn)贊和在看就是最大的支持??

          瀏覽 72
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕 成人 | 手机黄色在线 | 日韩aⅴ网站 | 日韩美女啪啪 | 天堂av一区在线观看 |