webpack4搭建的一次嘗試

目前支持typescript,react,jsx,less,eslint,prettier,husky等javascript

具體的配置請查看:github.com/nvnvyezi/in…css

如需搭配electron,能夠查看:github.com/nvnvyezi/el…html

好了,正文開始,這不是一個文章,只做爲想本身搭建webpack的一個參考java

概念

Entry:指定webpack開始構建的入口模塊,從該模塊開始構建並計算出直接或間接依賴的模塊或者庫node

Output:告訴webpack如何命名輸出的文件以及輸出的目錄react

Loaders:因爲webpack只能處理javascript,因此咱們須要對一些非js文件處理成webpack可以處理的模塊,好比sass文件webpack

PluginsLoaders將各種型的文件處理成webpack可以處理的模塊,plugins有着很強的能力。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。但也是最複雜的一個。好比對js文件進行壓縮優化的UglifyJsPlugin插件git

Chunk:coding split的產物,咱們能夠對一些代碼打包成一個單獨的chunk,好比某些公共模塊,去重,更好的利用緩存。或者按需加載某些功能模塊,優化加載時間。在webpack3及之前咱們都利用CommonsChunkPlugin將一些公共代碼分割成一個chunk,實現單獨加載。在webpack4 中CommonsChunkPlugin被廢棄,使用SplitChunksPlugines6

webpack啓動參數

  • color 輸出結果帶彩色,好比:會用紅色顯示耗時較長的步驟
  • profile 輸出性能數據,能夠看到每一步的耗時
  • progress 輸出當前編譯的進度,以百分比的形式呈現
  • display-modules 默認狀況下 node_modules 下的模塊會被隱藏,加上這個參數能夠顯示這些被隱藏的模塊
  • display-error-details 輸出詳細的錯誤信息

webpack4特性

  • Webpack4須要與webpack-cli一塊兒使用
  • 新添了mode屬性,
    • development
      • Process.env.NODE_ENV = development,需在啓動時設置NODE_ENV=development,不然在編譯過程當中取不到該值
      • 默認開啓如下插件,利用持久化緩存
      • namedChunksPlugin:以名稱固化chunk id,
      • namemodulesPlugin:以名稱固化module id
    • production
      • Process.env.NODE_ENV = production,一樣需配置
      • 默認開啓如下插件
      • SideEffectsFlagPluginUglifyJsPlugin 用於 tree-shaking
      • FlagDependencyUsagePlugin :編譯時標記依賴
      • FlagIncludedChunksPlugin :標記子chunks,防子chunks屢次加載
      • ModuleConcatenationPlugin :做用域提高(scope hosting),預編譯功能,提高或者預編譯全部模塊到一個閉包中,提高代碼在瀏覽器中的執行速度
      • NoEmitOnErrorsPlugin :在輸出階段時,遇到編譯錯誤跳過
      • OccurrenceOrderPlugin :給常用的ids更短的值
      • SideEffectsFlagPlugin :識別 package.json 或者 module.rules 的 sideEffects 標誌(純的 ES2015 模塊),安全地刪除未用到的 export 導出
      • UglifyJsPlugin :刪除未引用代碼,並壓縮
  • 移除 CommonsChunkPlugin插件,取而代之的是兩個新的配置項(optimization.splitChunks 和 optimization.runtimeChunk)
  • module.loaders 替換爲 modules.rules
  • webpack4 增長了 WebAssembly 的支持,能夠直接 import/export wasm 模塊,也能夠經過編寫 loaders 直接 import C++/C/Rust

splitChunks

能夠參考https://segmentfault.com/a/1190000013476837github

extra-text-webpack-plugin

關於[hash][chunkhash]的區別,簡單來講,[hash]是編譯(compilation)後的hash值,compilation對象表明某個版本的資源對應的編譯進程。項目中任何一個文件改動,webpack就會從新建立compilation對象,而後計算新的compilation的hash值,全部的編譯輸出文件名都會使用相同的hash指紋,改一個就一塊兒變。而[chunkhash]是根據具體模塊文件的內容計算所得的hash值,某個文件的改動只會影響它自己的hash指紋,不會影響其餘文件。

hash/chunkhash:

hash:在 webpack 一次構建中會產生一個 compilation 對象,該 hash 值是對 compilation 內全部的內容計算而來的

與整個項目的構建有關。只要整個項目中有文件更改,就會產生新的hash值,而且全部的文件共用一個hash值。

hash通常是結合CDN緩存來使用,經過webpack構建以後,生成對應文件名自動帶上對應的MD5值。若是文件內容改變的話,那麼對應文件哈希值也會改變,對應的HTML引用的URL地址也會改變,觸發CDN服務器從源服務器上拉取對應數據,進而更新本地緩存。可是在實際使用的時候,這幾種hash計算仍是有必定區別。

compiler對象表明的是配置完備的Webpack環境。 compiler對象只在Webpack啓動時構建一次,由Webpack組合全部的配置項構建生成。

compilation對象表明某個版本的資源對應的編譯進程。當使用Webpack的development中間件時,每次檢測到項目文件有改動就會建立一個compilation,進而可以針對改動生產全新的編譯文件。compilation對象包含當前模塊資源、待編譯文件、有改動的文件和監聽依賴的全部信息。

compiler表明配置好的webpack環境,compilation針對隨時可變得項目文件,只要文件有改動就會從新建立。

chunkhash:每個 chunk 都根據自身的內容計算而來。

根據不一樣的entry進行文件依賴分析,構建對應的chunk,生成對應的hash值,便可以將一些公共庫單獨打包構建,只要不改動公共庫的代碼,生成的hash值就不變。

保證了在線上構建的時候只要文件內容沒有更改就不會重複構建

contenthash:在js中引用css時,保證css不變的狀況下hash值不變

juejin.im/post/5a4502…

分析webpack中的Compiler/Compilation/Stats對象及構建順序:github.com/liangklfang…

tsconfig.json

概述

若是一個目錄下存在一個tsconfig.json文件,那麼它意味着這個目錄是TypeScript項目的根目錄。tsconfig.json文件中指定了用來編譯這個項目的根文件和編譯選項。 一個項目能夠經過如下方式之一來編譯:

使用tsconfig.json

  • 不帶任何輸入文件的狀況下調用tsc,編譯器會從當前目錄開始去查找tsconfig.json文件,逐級向上搜索父目錄。
  • 不帶任何輸入文件的狀況下調用tsc,且使用命令行參數--project(或-p)指定一個包含tsconfig.json文件的目錄。

當命令行上指定了輸入文件時,tsconfig.json文件會被忽略

配置示例

{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true
  },
  "files": [
    "app.ts",
    "foo.ts",
  ],
  // 或者使用include,exclude指定待編譯文件
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
  ]
}
複製代碼

compilerOptions 用來配置編譯選項,files 用來指定待編譯文件。

這裏的待編譯文件是指入口文件,任何被入口文件依賴的文件

files 屬性是一個數組,數組元素能夠是相對文件路徑和絕對文件路徑。

includeexclude 屬性也是一個數組,但數組元素是相似 glob 的文件模式。它支持的 glob 通配符包括:

  • * :匹配 0 或多個字符(注意:不含路徑分隔符)
  • ? :匹配任意單個字符(注意:不含路徑分隔符)
  • **/ :遞歸匹配任何子路徑

TS 文件指拓展名爲 .ts.tsx.d.ts 的文件。若是開啓了 allowJs 選項,那 .js.jsx 文件也屬於 TS 文件。

若是僅僅包含一個 * 或者 .* ,那麼只有TS 文件纔會被包含。

若是 filesinclude 都未設置,那麼除了 exclude 排除的文件,編譯器會默認包含路徑下的全部 TS 文件

若是同時設置 filesinclude ,那麼編譯器會把二者指定的文件都引入。

若是未設置 exclude ,那其默認值爲 node_modulesbower_componentsjspm_packages 和編譯選項 outDir 指定的路徑。

exclude 只對 include 有效,對 files 無效。即 files 指定的文件若是同時被 exclude 排除,那麼該文件仍然會被編譯器引入。

前面提到,任何被 filesinclude 引入的文件的依賴會被自動引入。 反過來,若是 B.tsA.ts 依賴,那麼 B.ts 不能被 exclude 排除,除非 A.ts 也被排除了。

有一點要注意的是,編譯器不會引入疑似爲輸出的文件。好比,若是引入的文件中包含 index.ts ,那麼 index.d.tsindex.js 就會被排除。一般來講,只有拓展名不同的文件命名法是不推薦的。

tsconfig.json 也能夠爲空文件,這種狀況下會使用默認的編譯選項來編譯全部默認引入的文件。

官方編譯選項列表:www.tslang.cn/docs/handbo…

能夠參考:www.tslang.cn/docs/handbo…

tslint/eslint選擇

ts.xcatliu.com/engineering…

Eslint規則:eslint.cn/docs/user-g…

參考掘金的eslint;juejin.im/post/5b3859…

react配置eslint一些規則: segmentfault.com/a/119000001…

eslint 配置項
  • root 限定配置文件的使用範圍
  • parser 指定eslint的解析器
  • parserOptions 設置解析器選項
  • extends 指定eslint規範
  • plugins 引用第三方的插件
  • env 指定代碼運行的宿主環境
  • rules 啓用額外的規則或覆蓋默認的規則
  • globals 聲明在代碼中的自定義全局變量

git提交檢測/husky/pre-commit/lint-staged

husky繼承了Git下全部的鉤子,在觸發鉤子的時候,husky能夠阻止不合法的commit,push等等。

husky是一個npm包,安裝後,能夠很方便的在package.json配置git hook 腳本 。

好比,在 package.json 內配置如

"scripts": {
    "lint": "eslint src"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run lint"
    }
  },
複製代碼

那麼,在後續的每一次git commit 以前,都會執行一次對應的 hook 腳本npm run lint 。其餘hook同理

pre-commit:github.com/PaicFE/blog…

lint-staged: github.com/okonet/lint…

prettire配置

prettier.io/docs/en/opt…

優化

  1. include & exclude
  2. babel-loader
  • cacheDirectory:默認值爲 false。當有設置時,指定的目錄將用來緩存 loader 的執行結果。以後的 webpack 構建,將會嘗試讀取緩存,來避免在每次執行時,可能產生的、高性能消耗的 Babel 從新編譯過程(recompilation process)。若是設置了一個空值 (loader: 'babel-loader?cacheDirectory') 或者 true (loader: babel-loader?cacheDirectory=true),loader 將使用默認的緩存目錄 node_modules/.cache/babel-loader,若是在任何根目錄下都沒有找到 node_modules 目錄,將會降級回退到操做系統默認的臨時文件目錄。
  1. 引入babel runtime,避免重複引入
  2. resolve.modules解析時搜索的目錄
  3. resolve.mainFields用於配置第三方模塊使用那個入口文件

安裝的第三方模塊中都會有一個 package.json文件,用於描述這個模塊的屬性,其中有些字段用於描述入口文件在哪裏,resolve.mainFields 用於配置採用哪一個字段做爲入口文件的描述。

能夠存在多個字段描述入口文件的緣由是由於有些模塊能夠同時用在多個環境中,針對不一樣的運行環境須要使用不一樣的代碼。 以 isomorphic-fetch API 爲例,它是 Promise的一個實現,但可同時用於瀏覽器和 Node.js 環境。

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

  2. resolve.extensions在導入語句沒帶文件後綴時,webpack自動帶上後綴去嘗試查詢文件是否存在

    1. 後綴列表儘量小
    2. 頻率最高的往前方
    3. 導出語句裏儘量帶上後綴
  3. module.noParse讓webpack忽略對部分沒采用模塊化的文件的遞歸解析處理

    1. 被忽略掉的文件裏不該該包含 import 、 require 、 define 等模塊化語句
  4. 使用動態連接庫

    1. webapck.DllPlugin
      1. context (optional): manifest 文件中請求的上下文(context)(默認值爲 webpack 的上下文(context))
      2. name: 暴露出的 DLL 的函數名 (TemplatePaths: [hash] & [name] )
      3. path: manifest json 文件的絕對路徑 (輸出文件)`
    2. webpack.DllReferencePlugin
      1. context: (絕對路徑) manifest (或者是內容屬性)中請求的上下文
      2. manifest: 包含 contentname 的對象,或者在編譯時(compilation)的一個用於加載的 JSON manifest 絕對路徑
      3. content (optional): 請求到模塊 id 的映射 (默認值爲 manifest.content)
      4. name (optional): dll 暴露的地方的名稱 (默認值爲 manifest.name) (可參考 externals)
      5. scope (optional): dll 中內容的前綴
      6. sourceType (optional): dll 是如何暴露的 (libraryTarget)
    3. libraryTargetlibrary
      1. output.libraryTarget 配置以何種方式導出庫。
      2. output.library 配置導出庫的名稱。 它們一般搭配在一塊兒使用。
    4. 推薦參考: segmentfault.com/a/119000001…
  5. HappyPack: 讓Webpack把任務分解給多個子進程去併發的執行,子進程處理完後再把結果發送給主進程。

    1. id: String 用惟一的標識符 id 來表明當前的 HappyPack 是用來處理一類特定的文件.

      loaders: Array 用法和 webpack Loader 配置中同樣.

      threads: Number 表明開啓幾個子進程去處理這一類型的文件,默認是3個,類型必須是整數。

      verbose: Boolean 是否容許 HappyPack 輸出日誌,默認是 true。

      threadPool: HappyThreadPool 表明共享進程池,即多個 HappyPack 實例都使用同一個共享進程池中的子進程去處理任務,以防止資源佔用過多。

      verboseWhenProfiling: Boolean 開啓webpack --profile ,仍然但願HappyPack產生輸出。

      debug: Boolean 啓用debug 用於故障排查。默認 false

  6. ParallelUglifyPlugin:能夠把對JS文件的串行壓縮變爲開啓多個子進程並行執行&oq=能夠把對JS文件的串行壓縮變爲開啓多個子進程並行執行

  7. 在支持es6的環境中直接使用es6,不進行轉換

  8. splitChunks: 提取公共代碼

  9. 區分環境,使用mode

  10. 代碼分離

相關文章
相關標籤/搜索