webpack從入門到放棄

webpack構建流程

從啓動webpack構建到輸出結果經歷了一系列過程:javascript

  1. 解析webpack.config.js配置參數,調用shell並追加命令行參數,經過 optimist將前二者參數整合成 options 對象傳到了下一個流程的控制對象中
  2. 註冊全部配置的插件,讓插件監聽webpack構建生命週期的事件節點,以作出對應的反應。
  3. 從配置的entry入口文件開始解析文件構建AST語法樹,找出每一個文件所依賴的文件,遞歸下去。
  4. 在解析文件遞歸的過程當中根據文件類型和loader配置找出合適的loader用來對文件進行轉換。
  5. 遞歸完後獲得每一個文件的最終結果,根據entry配置生成代碼塊chunk。
  6. 輸出全部chunk到文件系統。

入口和上下文(entry and context)

entry

指示 webpack 應該使用哪一個模塊,來做爲構建其內部依賴圖的開始css

  • 單入口

entry: './src/app.js'html

等同於下面寫法:vue

entry: {
    main: './src/app.js'
  }
複製代碼
  • 對象語法

分離 應用程序(app) 和 第三方庫(vendor) 入口java

entry: {
    app: './src/main.js',
    vendor: './src/jquery.js'
  }
複製代碼

這告訴咱們 webpack 從 main.js 和 jquery.js 開始建立依賴圖(dependency graph)。這些依賴圖是彼此徹底分離、互相獨立的。node

context

webpack 編譯時的基礎目錄,entry和loader 會相對於此目錄查找react

默認值爲當前目錄,不建議修改jquery

出口(output)

告訴 webpack 在哪裏輸出它所建立的 bundleswebpack

output: {
    path: path.join(__dirname, 'dist'),
    publicPath: '/',
    filename: 'js/[name].js'
}
複製代碼

publicPath

用於指定打包後的文件須要加載的外部資源(如圖片、js、css等)的跟路徑git

默認值是一個空字符串 "",一般設置成"/"
靜態資源最終訪問路徑 = output.publicPath + 資源loader或插件等配置路徑

  • loader 輸出圖片文件配置
{ name: 'imgs/[name].[ext]' }
// 那麼圖片最終的訪問路徑爲
output.publicPath('/') + 'imgs/[name].[ext]' = '/imgs/[name].[ext]'
複製代碼
  • plugin 提取css文件配置:
new ExtractTextPlugin('css/[name].[contenthash:10].css')
// html中加載css打包後代碼
<link href="/css/app.9502b0c565.css" rel="stylesheet">
複製代碼
  • html中加載js打包後代碼
<script type="text/javascript" src="/js/runtime.4ece365fd5.js"></script>
複製代碼

path

打包文件輸出的目錄

建議絕對路徑;默認值爲當前路徑。
path 中用使用 [hash] 模板可用於版本回歸

output: {
    path: path.resolve('./dist/[hash:8]/')
}
複製代碼

loader

loader 讓 webpack 可以去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)

注意:module.loaders 改成 module.rules;鏈式loader

  • webpack1語法
module: {
    loaders: [{
        test: /\.less$/,
        loader: "style!css!less"
    })
}
複製代碼
  • webpack二、3語法
module: {
    rules: [{
        test: /\.less$/,
        use: [
            "style-loader",
            "css-loader",
            "less-loader"
        ]
    }]
}
複製代碼

文件類

raw-loader 加載文件原始內容,好比.txt文件

file-loader 將文件發送到打包後文件夾中

{
    test: /\.(gif|png|jpe?g|svg)$/,
    use: [{
        loader: 'file-loader',
        options:{}
    }]
}
複製代碼

默認輸出到output的根目錄下,name爲32爲hash值

名稱 類型 默認值 描述
name {String | Funciton} [hash].[ext] 自定義文件名

placeholders

名稱 類型 默認值 描述
[ext] {String} file.extname 資源擴展名
[name] {String} file.name 資源名
[path] {String} file.dirname 資源路徑
[hash] {String} md5 內容的哈希值

url-loader 功能相似file-loader

對file-loader的擴展,能夠設置小圖片轉換base64圖片

{
    test: /\.(png|jpg|gif)$/,
        use: [
        {
            loader: 'url-loader',
            options: {
                limit:5000,
                name: 'img/[name].[ext]?[hash]'
            }
        }
    ]
}
複製代碼

轉換編譯類

script-loader

在全局上下文(global context)執行一次 JS腳本,就像你在網頁上經過<script>把它們引進來同樣。

babel-loader

因爲瀏覽器只能讀懂ES5語法,須要babel將ES2015+語法編譯爲ES5語法

  1. 安裝
    npm install babel-loader babel-core babel-preset-env webpack
  2. 用法
{
    test: /\.js$/,
    use: {
        loader: 'babel-loader',
        exclude: /node_modules/,
        options: {}
    }
}
複製代碼

options

  • cacheDirectory:默認值爲 false。當有設置時,指定的目錄將用來緩存 loader 的執行結果
  • babelrc 默認true,設置false,.babelrc將不會啓用

ts-loader 像 JavaScript 同樣加載 TypeScript 2.0+

模版類

html-loader 解決html里加載圖片問題

minimize:true 壓縮html文件

handlebars-loader 加載handlebars文件並編譯爲html文件

handlebars-template-loader 解決handlebars圖片路徑問題

markup-inline-loader

將內聯的 SVG/MathML 文件轉換爲 HTML。在應用於圖標字體,或將 CSS 動畫應用於 SVG 時很是有用

{
    test: /\.html$/,
    use: [
      'html-loader',
      'markup-inline-loader'
    ]
}
複製代碼

html中使用:
<img markup-inline src="./_images/camera.svg" />
<img data-markup-inline src="./_images/camera.svg" />

樣式類

style-loader 將模塊的導出做爲樣式添加到 DOM 中

css代碼放入js代碼裏再加入到html裏

css-loader 解析 CSS 文件後,使用 import 加載,而且返回 CSS 代碼

獲得css代碼

less-loader 加載和轉譯 LESS 文件

sass-loader 加載和轉譯 SASS/SCSS 文件

獲得css文件

postcss 使用 PostCSS 加載和轉譯 CSS 文件

後處理css文件,對css文件作語法分析,真正的核心操做,依賴於postcss龐大的插件羣體 postcss插件
好比css的語法驗證,壓縮,支持變量和混入語法

  • autoprefixer 補全瀏覽器前綴
  • postcss-import css文件中使用@import引入其餘樣式文件,可是使用autoprefixer發現,import進來的樣式沒有處理
postcss: function(webpack) {
  return [
    postcssImport({
      addDependencyTo: webpack
    }),
    autoprefixer
  ]
}
複製代碼

清理和測試類

mocha-loader 使用 mocha 測試(瀏覽器/NodeJS)

eslint-loader 使用 ESLint 清理代碼

jshint-loader 使用 JSHint 清理代碼

框架類

vue-loader 加載和轉譯 Vue 組件

angular2-template-loader 加載和轉譯 Angular 組件

插件

loader 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量

html-webpack-plugin 生成html文件

  • 爲html文件中引入的外部資源如script、link動態添加每次compile後的hash,防止引用緩存的外部文件問題
  • 能夠生成建立html入口文件,好比單頁面能夠生成一個html文件入口,配置N個html-webpack-plugin能夠生成N個頁面入口
new htmlWebpackPlugin(options)
複製代碼
名稱 類型 默認值 描述
title {String} `` 用於生成的HTML文檔的標題
filename {String} 'index.html' 生成html的文件名
template {String} `` 模版路徑及文件名(路徑相對與output.context)
inject {Boolean|String} true 當傳遞true或'body'全部JavaScript資源將被放置在正文元素的底部。'head'將腳本放置在head元素中,false不會將腳本放進html中
favicon {String} `` 將給定的圖標路徑添加到輸出HTML
minify {Boolean|Object} true 縮小輸出html html-minifier
hash {Boolean} false true:將webpack全部包含的腳本和CSS文件附加一個獨特的編譯哈希。這對緩存清除很是有用
cache {Boolean} true 僅在文件被更改時才發出文件
showErrors {Boolean} true 錯誤細節將寫入HTML頁面
chunks {?} ? 容許添加的chunk名
chunksSortMode {String|Function} auto 容許控制chunk在被包含到HTML以前應該如何排序。容許的值是'none'不分類 | 'auto'按塊ID排序 | 'dependency'經過其「父項」屬性對塊之間的依賴關係進行排序 | 'manual' | {Function}
excludeChunks {String} `` 容許您跳過一些chunk
xhtml {Boolean} false 若是true將link標籤呈現爲自動關閉(符合XHTML)
  • chunks按照順序加載
chunksSortMode: function (chunk1, chunk2) {
    var order = ['common', 'public', 'index'];
    var order1 = order.indexOf(chunk1.names[0]);
    var order2 = order.indexOf(chunk2.names[0]);
    return order1 - order2;  
}
複製代碼

extract-text-webpack-plugin

webpack 把全部的資源都當成了一個模塊, CSS,Image, JS 字體文件資源, 都打包到一個 bundle.js 文件中

它將*.css輸入塊中的全部必需模塊移動到單獨的CSS文件中
new ExtractTextPlugin([id: string], filename: string, [options])

  1. id 該插件實例的惟一標誌,通常是不會傳的,其本身會生成。
  2. filename 文件名。能夠是[name]、[id]、[contenthash] [name]:將會和entry中的chunk的名字一致 [id]:chunk 的數量 [contenthash]:根據內容生成hash值
  3. options allchunk:是否將全部額外的chunk都壓縮成一個文件 disable:禁止使用插件 ignoreOrder: 禁用順序檢查 (這對 CSS 模塊頗有用!),默認 false
  • extract 配置:
const ExtractTextPlugin = require('extract-text-webpack-plugin')
module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",//編譯後用什麼loader來提取css文件
          publicPath:, //重寫此 loader 的 publicPath 配置
          use: "css-loader" //須要什麼樣的loader去編譯文件
        })
      }
    ]
  }
複製代碼

CopyWebpackPlugin 拷貝資源插件

CopyWebpackPlugin([
        {
            context: 'global/img',
            from: '**/*',
            to:'img/common'
        },
        {
            from: 'img',
            to:'img'
        },
        {
            from :'global/lib/es5-shim-sham.js'
        }
])
複製代碼

from 定義要拷貝的源目錄.
to 定義要拷盤的目標目錄.
context 上下文.
flatten 只拷貝文件無論文件夾 默認是false.
ignore 忽略拷貝指定的文件 能夠用模糊匹配.
force 強制覆蓋先前的插件 可選 默認false.

UglifyJsPlugin 壓縮js文件

new webpack.optimize.UglifyJsPlugin(options)
複製代碼
名稱 類型 默認值 描述
test {RegExp|Array<RegExp>} /.js$/i 匹配文件
include {RegExp|Array<RegExp>} undefined 包含目錄
exclude {RegExp|Array<RegExp>} undefined 非匹配目錄
cache {Boolean|String} false 啓用文件緩存;cache: 'path/to/cache'
parallel {Boolean|Number} false 使用多進程並行運行來提升構建速度
sourceMap {Boolean} false 使用源映射將錯誤消息位置映射到模塊(這會減慢編譯速度) ⚠️ cheap-source-map 選項不適用於這個插件
uglifyOptions {Object} {...defaults} uglify 選項

webpack.optimize.UglifyJsPlugin()遇到的 Unexpected token: operator (>) from UglifyJs問題可使用 uglifyjs-webpack-plugin插件

DefinePlugin 容許在編譯時(compile time)配置的全局常量

new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify('production')
})
複製代碼

CleanWebpackPlugin 打包前清理dist目錄

new CleanWebpackPlugin(['./dist'])

webpack自帶插件

CommonsChunkPlugin 提取 chunks 之間共享的通用模塊

webpack將多個模塊打包以後的代碼集合稱爲chunk

將公共js代碼提取到單獨文件裏

  • 是一個可選的用於創建一個獨立文件(又稱做 chunk)的功能
  • 經過將公共模塊拆出來,最終合成的文件可以在最開始的時候加載一次,便存到緩存中供後續使用
  • 語法: new webpack.optimize.CommonsChunkPlugin(options)
  • 配置
  1. 決定生成chunk的參數: name, names, async
  • name: string: 公共chunk的名字
  • names: string[]: 和name同樣,不過傳入的是一個數組
  • async: boolean|string: 把公共代碼提取到一個懶加載的chunk,在被使用到時才進行下載
  1. 決定被提取的chunk: chunks, children, deepChildren
  2. 決定提取條件: minChunks
  • minChunks: number|infinity|function(module,count)->boolean: 若是傳入數字(默認值爲3),就是告訴webpack,只有當模塊重複的次數大於等於該數字時,這個模塊纔會被提取出來;Infinity表示不會打包多餘的第三方庫;當傳入爲函數時,全部符合條件的chunk中的模塊都會被傳入該函數作計算,返回true的模塊會被提取到目標chunk
module.exports = {
    entry: {
        main1: '/src/main1.js',
        main2: '/src/main2.js',
        jquery:["jquery"],
        vue:["vue"]
    },
    plugins: [
        new CommonsChunkPlugin({
            name: ["common",'jquery','vue'],//對應於上面的entry的key
            minChunks:2
        })
    ]
};
複製代碼

打包後jquery和vue會生成獨立chunk,main1和main2中的公共業務模塊會打包到common.js中;minChunks爲infinity時,公共業務模塊會分別打包到main1.js和main2.js中
webpack用插件CommonsChunkPlugin進行打包的時候 將符合引用次數(minChunks)的模塊打包到name參數的數組的第一個塊裏(chunk),而後數組後面的塊依次打包,最後一個塊包含webpack生成的在瀏覽器上使用各個塊的加載代碼

HotModuleReplacementPlugin 熱模塊替換

new webpack.HotModuleReplacementPlugin()
複製代碼
devServer: {
    hot: true // 激活服務器的HMR
}
複製代碼

其餘

cross-env

在不一樣系統環境下設置變量

webpack-dev-server

  • 開發環境用於調試報錯信息等,生成一個開發用的服務器,在文件有變化的時候自動給咱們打包,而後刷新頁面
  • 它還有個模塊熱替換的功能 .. 就是它能夠只替換有變化的地方 .. 不須要刷新整個頁面 ...

優化

優化輸出

壓縮css

css-loader?minimize去除css文件裏有不少空格和tab

tree-shaking

藉助es6 import export語法靜態性的特色來刪掉export可是沒有import過的東西

  • 配置babel讓它在編譯轉化es6代碼時不把import export轉換爲cmd的module.export,配置以下:
"presets": [
    [
      "es2015",
      {
        "modules": false
      }
    ]
]
複製代碼

優化 UglifyJsPlugin

new UglifyJsPlugin({
    // 最緊湊的輸出
    beautify: false,
    // 刪除全部的註釋
    comments: false,
    compress: {
      // 在UglifyJs刪除沒有用到的代碼時不輸出警告  
      warnings: false,
      // 刪除全部的 `console` 語句
      // 還能夠兼容ie瀏覽器
      drop_console: true,
      // 內嵌定義了可是隻用到一次的變量
      collapse_vars: true,
      // 提取出出現屢次可是沒有定義成變量去引用的靜態值
      reduce_vars: true,
    }
})
複製代碼

imagemin-webpack-plugin壓縮圖片

更快的構建

縮小文件搜索範圍

  • 配置模塊庫.
    在js裏出現import 'redux'這樣不是相對也不是絕對路徑的寫法時會去node_modules目錄下找。可是默認的配置會採用向上遞歸搜索的方式去尋找node_modules,但一般項目目錄裏只有一個node_modules在項目根目錄
module.exports = {
    resolve: {
        modules: [path.resolve(__dirname, 'node_modules')]
    }
};
複製代碼
  • 配置loader
{
    test: /\.js$/,
    loader: 'babel-loader',
    include: path.resolve(__dirname, 'src')
}
複製代碼

開啓 babel-loader 緩存

babel編譯過程很耗時,好在babel-loader提供緩存編譯結果選項,在重啓webpack時不須要創新編譯而是複用緩存結果減小編譯流程。babel-loader緩存機制默認是關閉的,打開的配置以下:

{
test: /\.js$/,
      loader: 'babel-loader?cacheDirectory',
}
複製代碼

使用 alias

resolve.alias 配置路徑映射。 發佈到npm的庫大多數都包含兩個目錄,一個是放着cmd模塊化的lib目錄,一個是把全部文件合成一個文件的dist目錄,多數的入口文件是指向lib裏面下的。
默認狀況下webpack會去讀lib目錄下的入口文件再去遞歸加載其它依賴的文件這個過程很耗時,alias配置可讓webpack直接使用dist目錄的總體文件減小文件遞歸解析。配置以下:

module.exports = {
  resolve: {
    alias: {
      'moment': 'moment/min/moment.min.js',
      'react': 'react/dist/react.js',
      'react-dom': 'react-dom/dist/react-dom.js'
    }
  }
};
複製代碼

使用 noParse

module.noParse 配置哪些文件能夠脫離webpack的解析。 有些庫是自成一體不依賴其餘庫的沒有使用模塊化的,好比jquey、momentjs、chart.js,要使用它們必須總體所有引入。
webpack是模塊化打包工具徹底沒有必要去解析這些文件的依賴,由於它們都不依賴其它文件體積也很龐大,要忽略它們配置以下:

module.exports = {
  module: {
    noParse: /node_modules\/(jquey|moment|chart\.js)/
  }
};
複製代碼
相關文章
相關標籤/搜索