国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

webpack優化

ChanceWong / 1154人閱讀

摘要:使用要給項目構建接入動態鏈接庫的思想,需要完成以下事情把網頁依賴的基礎模塊抽離出來,打包到一個個多帶帶的動態鏈接庫中去。接入已經內置了對動態鏈接庫的支持,需要通過個內置的插件接入,它們分別是插件用于打包出一個個多帶帶的動態鏈接庫文件。

webpack優化
查看所有文檔頁面:全棧開發,獲取更多信息。

原文鏈接:webpack優化,原文廣告模態框遮擋,閱讀體驗不好,所以整理成本文,方便查找。

優化開發體驗

優化構建速度。在項目龐大時構建耗時可能會變的很長,每次等待構建的耗時加起來也會是個大數目。

縮小文件搜索范圍

使用 DllPlugin

使用 HappyPack

使用 ParallelUglifyPlugin

優化使用體驗。通過自動化手段完成一些重復的工作,讓我們專注于解決問題本身。

使用自動刷新

開啟模塊熱替換

優化輸出質量

優化輸出質量的目的是為了給用戶呈現體驗更好的網頁,例如減少首屏加載時間、提升性能流暢度等。 這至關重要,因為在互聯網行業競爭日益激烈的今天,這可能關系到你的產品的生死。

優化輸出質量本質是優化構建輸出的要發布到線上的代碼,分為以下幾點:

減少用戶能感知到的加載時間,也就是首屏加載時間。

區分環境

壓縮代碼

CDN 加速

使用 Tree Shaking

提取公共代碼

按需加載

提升流暢度,也就是提升代碼性能。

使用 Prepack

開啟 Scope Hoisting

縮小文件搜索范圍

Webpack 啟動后會從配置的 Entry 出發,解析出文件中的導入語句,再遞歸的解析。 在遇到導入語句時 Webpack 會做兩件事情:

根據導入語句去尋找對應的要導入的文件。例如 require("react") 導入語句對應的文件是 ./node_modules/react/react.js,require("./util") 對應的文件是 ./util.js

根據找到的要導入文件的后綴,使用配置中的 Loader 去處理文件。例如使用 ES6 開發的 JavaScript 文件需要使用 babel-loader 去處理。

優化 loader 配置

由于 Loader 對文件的轉換操作很耗時,需要讓盡可能少的文件被 Loader 處理。

在 Module 中介紹過在使用 Loader 時可以通過 testincludeexclude 三個配置項來命中 Loader 要應用規則的文件。 為了盡可能少的讓文件被 Loader 處理,可以通過 include 去命中只有哪些文件需要被處理。

以采用 ES6 的項目為例,在配置 babel-loader 時,可以這樣:

module.exports = {
  module: {
    rules: [
      {
        // 如果項目源碼中只有 js 文件就不要寫成 /.jsx?$/,提升正則表達式性能
        test: /.js$/,
        // babel-loader 支持緩存轉換出的結果,通過 cacheDirectory 選項開啟
        use: ["babel-loader?cacheDirectory"],
        // 只對項目根目錄下的 src 目錄中的文件采用 babel-loader
        include: path.resolve(__dirname, "src"),
      },
    ]
  },
};


你可以適當的調整項目的目錄結構,以方便在配置 Loader 時通過 include 去縮小命中范圍。
優化 resolve.modules 配置

在 Resolve 中介紹過 resolve.modules 用于配置 Webpack 去哪些目錄下尋找第三方模塊。

resolve.modules 的默認值是 ["node_modules"],含義是先去當前目錄下的 ./node_modules 目錄下去找想找的模塊,如果沒找到就去上一級目錄 ../node_modules 中找,再沒有就去 ../../node_modules 中找,以此類推,這和 Node.js 的模塊尋找機制很相似。

當安裝的第三方模塊都放在項目根目錄下的 ./node_modules 目錄下時,沒有必要按照默認的方式去一層層的尋找,可以指明存放第三方模塊的絕對路徑,以減少尋找,配置如下:

module.exports = {
  resolve: {
    // 使用絕對路徑指明第三方模塊存放的位置,以減少搜索步驟
    // 其中 __dirname 表示當前工作目錄,也就是項目根目錄
    modules: [path.resolve(__dirname, "node_modules")]
  },
};
優化 resolve.mainFields 配置

在 Resolve 中介紹過 resolve.mainFields 用于配置第三方模塊使用哪個入口文件。

安裝的第三方模塊中都會有一個 package.json 文件用于描述這個模塊的屬性,其中有些字段用于描述入口文件在哪里,resolve.mainFields 用于配置采用哪個字段作為入口文件的描述。

可以存在多個字段描述入口文件的原因是因為有些模塊可以同時用在多個環境中,準對不同的運行環境需要使用不同的代碼。 以 isomorphic-fetch 為例,它是 fetch API 的一個實現,但可同時用于瀏覽器和 Node.js 環境。 它的 package.json 中就有2個入口文件描述字段:

{
  "browser": "fetch-npm-browserify.js",
  "main": "fetch-npm-node.js"
}   
isomorphic-fetch 在不同的運行環境下使用不同的代碼是因為 fetch API 的實現機制不一樣,在瀏覽器中通過原生的 fetch 或者 XMLHttpRequest 實現,在 Node.js 中通過 http 模塊實現。

resolve.mainFields 的默認值和當前的 target 配置有關系,對應關系如下:

targetweb 或者 webworker 時,值是 ["browser", "module", "main"]

target 為其它情況時,值是 ["module", "main"]

target 等于 web 為例,Webpack 會先采用第三方模塊中的 browser 字段去尋找模塊的入口文件,如果不存在就采用 module 字段,以此類推。

為了減少搜索步驟,在你明確第三方模塊的入口文件描述字段時,你可以把它設置的盡量少。 由于大多數第三方模塊都采用 main 字段去描述入口文件的位置,可以這樣配置 Webpack:

module.exports = {
  resolve: {
    // 只采用 main 字段作為入口文件描述字段,以減少搜索步驟
    mainFields: ["main"],
  },
};   
使用本方法優化時,你需要考慮到所有運行時依賴的第三方模塊的入口文件描述字段,就算有一個模塊搞錯了都可能會造成構建出的代碼無法正常運行。
優化 resolve.alias 配置

resolve.alias 配置項通過別名來把原導入路徑映射成一個新的導入路徑。

在實戰項目中經常會依賴一些龐大的第三方模塊,以 React 庫為例,安裝到 node_modules 目錄下的 React 庫的目錄結構如下:

├── dist
│   ├── react.js
│   └── react.min.js
├── lib
│   ... 還有幾十個文件被忽略
│   ├── LinkedStateMixin.js
│   ├── createClass.js
│   └── React.js
├── package.json
└── react.js

可以看到發布出去的 React 庫中包含兩套代碼:

一套是采用 CommonJS 規范的模塊化代碼,這些文件都放在 lib 目錄下,以 package.json 中指定的入口文件 react.js 為模塊的入口。

一套是把 React 所有相關的代碼打包好的完整代碼放到一個多帶帶的文件中,這些代碼沒有采用模塊化可以直接執行。其中 dist/react.js 是用于開發環境,里面包含檢查和警告的代碼。dist/react.min.js 是用于線上環境,被最小化了。

默認情況下 Webpack 會從入口文件 ./node_modules/react/react.js 開始遞歸的解析和處理依賴的幾十個文件,這會時一個耗時的操作。 通過配置 resolve.alias 可以讓 Webpack 在處理 React 庫時,直接使用多帶帶完整的 react.min.js 文件,從而跳過耗時的遞歸解析操作。

相關 Webpack 配置如下:

module.exports = {
  resolve: {
    // 使用 alias 把導入 react 的語句換成直接使用多帶帶完整的 react.min.js 文件,
    // 減少耗時的遞歸解析操作
    alias: {
      "react": path.resolve(__dirname, "./node_modules/react/dist/react.min.js"),
    }
  },
};

除了 React 庫外,大多數庫發布到 Npm 倉庫中時都會包含打包好的完整文件,對于這些庫你也可以對它們配置 alias

但是對于有些庫使用本優化方法后會影響到后面要講的使用 Tree-Shaking 去除無效代碼的優化,因為打包好的完整文件中有部分代碼你的項目可能永遠用不上。 一般對整體性比較強的庫采用本方法優化,因為完整文件中的代碼是一個整體,每一行都是不可或缺的。 但是對于一些工具類的庫,例如 lodash,你的項目可能只用到了其中幾個工具函數,你就不能使用本方法去優化,因為這會導致你的輸出代碼中包含很多永遠不會執行的代碼。

優化 resolve.extensions 配置

在導入語句沒帶文件后綴時,Webpack 會自動帶上后綴后去嘗試詢問文件是否存在。resolve.extensions 用于配置在嘗試過程中用到的后綴列表,默認是:

extensions: [".js", ".json"]

也就是說當遇到 require("./data") 這樣的導入語句時,Webpack 會先去尋找 ./data.js 文件,如果該文件不存在就去尋找 ./data.json 文件,如果還是找不到就報錯。

如果這個列表越長,或者正確的后綴在越后面,就會造成嘗試的次數越多,所以 resolve.extensions 的配置也會影響到構建的性能。 在配置 resolve.extensions 時你需要遵守以下幾點,以做到盡可能的優化構建性能:

后綴嘗試列表要盡可能的小,不要把項目中不可能存在的情況寫到后綴嘗試列表中。

頻率出現最高的文件后綴要優先放在最前面,以做到盡快的退出尋找過程。

在源碼中寫導入語句時,要盡可能的帶上后綴,從而可以避免尋找過程。例如在你確定的情況下把 require("./data") 寫成 require("./data.json")

相關 Webpack 配置如下:

module.exports = {
  resolve: {
    // 盡可能的減少后綴嘗試的可能性
    extensions: ["js"],
  },
};
優化 module.noParse 配置

module.noParse 配置項可以讓 Webpack 忽略對部分沒采用模塊化的文件的遞歸解析處理,這樣做的好處是能提高構建性能。 原因是一些庫,例如 jQuery 、ChartJS, 它們龐大又沒有采用模塊化標準,讓 Webpack 去解析這些文件耗時又沒有意義。

在上面的 優化 resolve.alias 配置 中講到多帶帶完整的 react.min.js 文件就沒有采用模塊化,讓我們來通過配置 module.noParse 忽略對 react.min.js 文件的遞歸解析處理, 相關 Webpack 配置如下:

const path = require("path");

module.exports = {
  module: {
    // 獨完整的 `react.min.js` 文件就沒有采用模塊化,忽略對 `react.min.js` 文件的遞歸解析處理
    noParse: [/react.min.js$/],
  },
};
注意被忽略掉的文件里不應該包含 importrequiredefine 等模塊化語句,不然會導致構建出的代碼中包含無法在瀏覽器環境下執行的模塊化語句。

以上就是所有和縮小文件搜索范圍相關的構建性能優化了,在根據自己項目的需要去按照以上方法改造后,你的構建速度一定會有所提升。

使用 DllPlugin

要給 Web 項目構建接入動態鏈接庫的思想,需要完成以下事情:

把網頁依賴的基礎模塊抽離出來,打包到一個個多帶帶的動態鏈接庫中去。一個動態鏈接庫中可以包含多個模塊。

當需要導入的模塊存在于某個動態鏈接庫中時,這個模塊不能被再次被打包,而是去動態鏈接庫中獲取。

當需要導入的模塊存在于某個動態鏈接庫中時,這個模塊不能被再次被打包,而是去動態鏈接庫中獲取。

為什么給 Web 項目構建接入動態鏈接庫的思想后,會大大提升構建速度呢? 原因在于包含大量復用模塊的動態鏈接庫只需要編譯一次,在之后的構建過程中被動態鏈接庫包含的模塊將不會在重新編譯,而是直接使用動態鏈接庫中的代碼。 由于動態鏈接庫中大多數包含的是常用的第三方模塊,例如 reactreact-dom,只要不升級這些模塊的版本,動態鏈接庫就不用重新編譯。

接入 Webpack

Webpack 已經內置了對動態鏈接庫的支持,需要通過2個內置的插件接入,它們分別是:

DllPlugin 插件:用于打包出一個個多帶帶的動態鏈接庫文件。

DllReferencePlugin 插件:用于在主要配置文件中去引入 DllPlugin 插件打包好的動態鏈接庫文件。

下面以基本的 React 項目為例,為其接入 DllPlugin,在開始前先來看下最終構建出的目錄結構:

├── main.js
├── polyfill.dll.js
├── polyfill.manifest.json
├── react.dll.js
└── react.manifest.json

其中包含兩個動態鏈接庫文件,分別是:

polyfill.dll.js 里面包含項目所有依賴的 polyfill,例如 Promise、fetch 等 API。

react.dll.js 里面包含 React 的基礎運行環境,也就是 reactreact-dom 模塊。

react.dll.js 文件為例,其文件內容大致如下:

var _dll_react = (function(modules) {
  // ... 此處省略 webpackBootstrap 函數代碼
}([
  function(module, exports, __webpack_require__) {
    // 模塊 ID 為 0 的模塊對應的代碼
  },
  function(module, exports, __webpack_require__) {
    // 模塊 ID 為 1 的模塊對應的代碼
  },
  // ... 此處省略剩下的模塊對應的代碼 
]));

可見一個動態鏈接庫文件中包含了大量模塊的代碼,這些模塊存放在一個數組里,用數組的索引號作為 ID。 并且還通過 _dll_react 變量把自己暴露在了全局中,也就是可以通過 window._dll_react 可以訪問到它里面包含的模塊。

其中 polyfill.manifest.jsonreact.manifest.json 文件也是由 DllPlugin 生成出,用于描述動態鏈接庫文件中包含哪些模塊, 以 react.manifest.json 文件為例,其文件內容大致如下:

See the Pen react.manifest.json by whjin (@whjin) on CodePen.


以上就是所有接入 DllPlugin 后最終編譯出來的代碼,接下來教你如何實現。

構建出動態鏈接庫文件

構建輸出的以下這四個文件:

├── polyfill.dll.js
├── polyfill.manifest.json
├── react.dll.js
└── react.manifest.json

和以下這一個文件:

├── main.js

是由兩份不同的構建分別輸出的。

動態鏈接庫文件相關的文件需要由一份獨立的構建輸出,用于給主構建使用。新建一個 Webpack 配置文件 webpack_dll.config.js 專門用于構建它們,文件內容如下:

See the Pen webpack_dll.config.js by whjin (@whjin) on CodePen.


注意:在 webpack_dll.config.js 文件中,DllPlugin 中的 name 參數必須和 output.library 中保持一致。 原因在于 DllPlugin 中的 name 參數會影響輸出的 manifest.json 文件中 name 字段的值, 而在 webpack.config.js 文件中 DllReferencePlugin 會去 manifest.json 文件讀取 name 字段的值, 把值的內容作為在從全局變量中獲取動態鏈接庫中內容時的全局變量名。
執行構建

在修改好以上兩個 Webpack 配置文件后,需要重新執行構建。 重新執行構建時要注意的是需要先把動態鏈接庫相關的文件編譯出來,因為主 Webpack 配置文件中定義的 DllReferencePlugin 依賴這些文件。

執行構建時流程如下:

如果動態鏈接庫相關的文件還沒有編譯出來,就需要先把它們編譯出來。方法是執行 webpack --config webpack_dll.config.js 命令。

在確保動態鏈接庫存在時,才能正常的編譯出入口執行文件。方法是執行 webpack 命令。這時你會發現構建速度有了非常大的提升。

使用 HappyPack

由于有大量文件需要解析和處理,構建是文件讀寫和計算密集型的操作,特別是當文件數量變多后,Webpack 構建慢的問題會顯得嚴重。 運行在 Node.js 之上的 Webpack 是單線程模型的,也就是說 Webpack 需要處理的任務需要一件件挨著做,不能多個事情一起做。

文件讀寫和計算操作是無法避免的,那能不能讓 Webpack 同一時刻處理多個任務,發揮多核 CPU 電腦的威力,以提升構建速度呢?

HappyPack 就能讓 Webpack 做到這點,它把任務分解給多個子進程去并發的執行,子進程處理完后再把結果發送給主進程。

由于 JavaScript 是單線程模型,要想發揮多核 CPU 的能力,只能通過多進程去實現,而無法通過多線程實現。

分解任務和管理線程的事情 HappyPack 都會幫你做好,你所需要做的只是接入 HappyPack。 接入 HappyPack 的相關代碼如下:

See the Pen HappyPack by whjin (@whjin) on CodePen.


接入 HappyPack 后,你需要給項目安裝新的依賴:

npm i -D happypack
HappyPack 原理

在整個 Webpack 構建流程中,最耗時的流程可能就是 Loader 對文件的轉換操作了,因為要轉換的文件數據巨多,而且這些轉換操作都只能一個個挨著處理。 HappyPack 的核心原理就是把這部分任務分解到多個進程去并行處理,從而減少了總的構建時間。

從前面的使用中可以看出所有需要通過 Loader 處理的文件都先交給了 happypack/loader 去處理,收集到了這些文件的處理權后 HappyPack 就好統一分配了。

每通過 new HappyPack() 實例化一個 HappyPack 其實就是告訴 HappyPack 核心調度器如何通過一系列 Loader 去轉換一類文件,并且可以指定如何給這類轉換操作分配子進程。

核心調度器的邏輯代碼在主進程中,也就是運行著 Webpack 的進程中,核心調度器會把一個個任務分配給當前空閑的子進程,子進程處理完畢后把結果發送給核心調度器,它們之間的數據交換是通過進程間通信 API 實現的。

核心調度器收到來自子進程處理完畢的結果后會通知 Webpack 該文件處理完畢。

使用 ParallelUglifyPlugin

在使用 Webpack 構建出用于發布到線上的代碼時,都會有壓縮代碼這一流程。 最常見的 JavaScript 代碼壓縮工具是 UglifyJS,并且 Webpack 也內置了它。

用過 UglifyJS 的你一定會發現在構建用于開發環境的代碼時很快就能完成,但在構建用于線上的代碼時構建一直卡在一個時間點遲遲沒有反應,其實卡住的這個時候就是在進行代碼壓縮。

由于壓縮 JavaScript 代碼需要先把代碼解析成用 Object 抽象表示的 AST 語法樹,再去應用各種規則分析和處理 AST,導致這個過程計算量巨大,耗時非常多。

為什么不把在使用 HappyPack中介紹過的多進程并行處理的思想也引入到代碼壓縮中呢?

ParallelUglifyPlugin 就做了這個事情。 當 Webpack 有多個 JavaScript 文件需要輸出和壓縮時,原本會使用 UglifyJS 去一個個挨著壓縮再輸出, 但是 ParallelUglifyPlugin 則會開啟多個子進程,把對多個文件的壓縮工作分配給多個子進程去完成,每個子進程其實還是通過 UglifyJS 去壓縮代碼,但是變成了并行執行。 所以 ParallelUglifyPlugin 能更快的完成對多個文件的壓縮工作。

使用 ParallelUglifyPlugin 也非常簡單,把原來 Webpack 配置文件中內置的 UglifyJsPlugin 去掉后,再替換成 ParallelUglifyPlugin,相關代碼如下:

See the Pen ParallelUglifyPlugin by whjin (@whjin) on CodePen.


給網頁注入以上腳本后,獨立打開的網頁就能自動刷新了。但是要注意在發布到線上時記得刪除掉這段用于開發環境的代碼。

開啟模塊熱替換

要做到實時預覽,除了在使用自動刷新中介紹的刷新整個網頁外,DevServer 還支持一種叫做模塊熱替換(Hot Module Replacement)的技術可在不刷新整個網頁的情況下做到超靈敏的實時預覽。 原理是當一個源碼發生變化時,只重新編譯發生變化的模塊,再用新輸出的模塊替換掉瀏覽器中對應的老模塊。

模塊熱替換技術的優勢有:

實時預覽反應更快,等待時間更短。

不刷新瀏覽器能保留當前網頁的運行狀態,例如在使用 Redux 來管理數據的應用中搭配模塊熱替換能做到代碼更新時 Redux 中的數據還保持不變。

總的來說模塊熱替換技術很大程度上的提高了開發效率和體驗。

模塊熱替換的原理

模塊熱替換的原理和自動刷新原理類似,都需要往要開發的網頁中注入一個代理客戶端用于連接 DevServer 和網頁, 不同在于模塊熱替換獨特的模塊替換機制。

DevServer 默認不會開啟模塊熱替換模式,要開啟該模式,只需在啟動時帶上參數 --hot,完整命令是 webpack-dev-server --hot

除了通過在啟動時帶上 --hot 參數,還可以通過接入 Plugin 實現,相關代碼如下:

const HotModuleReplacementPlugin = require("webpack/lib/HotModuleReplacementPlugin");

module.exports = {
  entry:{
    // 為每個入口都注入代理客戶端
    main:["webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server","./src/main.js"],
  },
  plugins: [
    // 該插件的作用就是實現模塊熱替換,實際上當啟動時帶上 `--hot` 參數,會注入該插件,生成 .hot-update.json 文件。
    new HotModuleReplacementPlugin(),
  ],
  devServer:{
    // 告訴 DevServer 要開啟模塊熱替換模式
    hot: true,      
  }  
};

在啟動 Webpack 時帶上參數 --hot 其實就是自動為你完成以上配置。

相比于自動刷新的代理客戶端,多出了后三個用于模塊熱替換的文件,也就是說代理客戶端更大了。

可見補丁中包含了 main.css 文件新編譯出來 CSS 代碼,網頁中的樣式也立刻變成了源碼中描述的那樣。

但當你修改 main.js 文件時,會發現模塊熱替換沒有生效,而是整個頁面被刷新了,為什么修改 main.js 文件時會這樣呢?

Webpack 為了讓使用者在使用了模塊熱替換功能時能靈活地控制老模塊被替換時的邏輯,可以在源碼中定義一些代碼去做相應的處理。

把的 main.js 文件改為如下:

See the Pen main.js by whjin (@whjin) on CodePen.


同時,為了不讓 babel-loader 輸出 ES5 語法的代碼,需要去掉 .babelrc 配置文件中的 babel-preset-env,但是其它的 Babel 插件,比如 babel-preset-react 還是要保留, 因為正是 babel-preset-env 負責把 ES6 代碼轉換為 ES5 代碼。

壓縮 CSS

CSS 代碼也可以像 JavaScript 那樣被壓縮,以達到提升加載速度和代碼混淆的作用。 目前比較成熟可靠的 CSS 壓縮工具是 cssnano,基于 PostCSS。

cssnano 能理解 CSS 代碼的含義,而不僅僅是刪掉空格,例如:

margin: 10px 20px 10px 20px 被壓縮成 margin: 10px 20px

color: #ff0000 被壓縮成 color:red

還有很多壓縮規則可以去其官網查看,通常壓縮率能達到 60%。

cssnano 接入到 Webpack 中也非常簡單,因為 css-loader 已經將其內置了,要開啟 cssnano 去壓縮代碼只需要開啟 css-loaderminimize 選項。 相關 Webpack 配置如下:

See the Pen cssnano by whjin (@whjin) on CodePen.


app_a6976b6d.css內容如下:

body{background:url(arch_ae805d49.png) repeat}h1{color:red}

可以看出到導入資源時都是通過相對路徑去訪問的,當把這些資源都放到同一個 CDN 服務上去時,網頁是能正常使用的。 但需要注意的是由于 CDN 服務一般都會給資源開啟很長時間的緩存,例如用戶從 CDN 上獲取到了 index.html 這個文件后, 即使之后的發布操作把 index.html 文件給重新覆蓋了,但是用戶在很長一段時間內還是運行的之前的版本,這會新的導致發布不能立即生效。

要避免以上問題,業界比較成熟的做法是這樣的:

針對 HTML 文件:不開啟緩存,把 HTML 放到自己的服務器上,而不是 CDN 服務上,同時關閉自己服務器上的緩存。自己的服務器只提供 HTML 文件和數據接口。

針對靜態的 JavaScript、CSS、圖片等文件:開啟 CDN 和緩存,上傳到 CDN 服務上去,同時給每個文件名帶上由文件內容算出的 Hash 值, 例如上面的 app_a6976b6d.css 文件。 帶上 Hash 值的原因是文件名會隨著文件內容而變化,只要文件發生變化其對應的 URL 就會變化,它就會被重新下載,無論緩存時間有多長。

采用以上方案后,在 HTML 文件中的資源引入地址也需要換成 CDN 服務提供的地址,例如以上的 index.html 變為如下:



  
  


并且 app_a6976b6d.css 的內容也應該變為如下:

也就是說,之前的相對路徑,都變成了絕對的指向 CDN 服務的 URL 地址。

如果你對形如 //cdn.com/id/app_a6976b6d.css 這樣的 URL 感到陌生,你需要知道這種 URL 省掉了前面的 http: 或者 https: 前綴, 這樣做的好處時在訪問這些資源的時候會自動的根據當前 HTML 的 URL 是采用什么模式去決定是采用 HTTP 還是 HTTPS 模式。

除此之外,如果你還知道瀏覽器有一個規則是同一時刻針對同一個域名的資源并行請求是有限制的話(具體數字大概4個左右,不同瀏覽器可能不同), 你會發現上面的做法有個很大的問題。由于所有靜態資源都放到了同一個 CDN 服務的域名下,也就是上面的 cdn.com。 如果網頁的資源很多,例如有很多圖片,就會導致資源的加載被阻塞,因為同時只能加載幾個,必須等其它資源加載完才能繼續加載。 要解決這個問題,可以把這些靜態資源分散到不同的 CDN 服務上去, 例如把 JavaScript 文件放到 js.cdn.com 域名下、把 CSS 文件放到 css.cdn.com 域名下、圖片文件放到 img.cdn.com 域名下, 這樣做之后 index.html 需要變成這樣:



  
  


使用了多個域名后又會帶來一個新問題:增加域名解析時間。是否采用多域名分散資源需要根據自己的需求去衡量得失。 當然你可以通過在 HTML HEAD 標簽中 加入  去預解析域名,以降低域名解析帶來的延遲。
用 Webpack 實現 CDN 的接入

總結上面所說的,構建需要實現以下幾點:

靜態資源的導入 URL 需要變成指向 CDN 服務的絕對路徑的 URL 而不是相對于 HTML 文件的 URL。

靜態資源的文件名稱需要帶上有文件內容算出來的 Hash 值,以防止被緩存。

不同類型的資源放到不同域名的 CDN 服務上去,以防止資源的并行加載被阻塞。

先來看下要實現以上要求的最終 Webpack 配置:

See the Pen CDN 的接入 by whjin (@whjin) on CodePen.


閱讀需要支付1元查看
<