使用 webpack 構建應用

如何使用webpack

npm init -y
npm install webapck webpack-cli --save-dev
touch webpack.config.js

webpack.config.js中下面添加內容javascript

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
};
  • entry:工程資源的入口,能夠是單個文件,也能夠是多個文件,經過每個資源入口,webpack會一次去尋找它的依賴進行模塊打包。咱們能夠把entry理解爲整個依賴樹的根,每一個入口都將對應一個最終生成的打包結果。
  • output:這是一個配置對象,經過它咱們能夠對最終打包的產物進行配置,這裏配置了兩個屬性,:css

    • path:打包資源放置的路勁,必須爲絕對路徑。
    • filename:打包結果的文件名。

定義好配置文件後,用npx webpack或者./node_modules/.bin/webpack執行html

使用loader

項目中須要引入一個css文件,若是直接用webpack去執行就會報錯,須要再webpack中加入loader機制java

module.exports = {
    ...
    module: {
        rules: [
            {
                // 用正則去匹配 .css 結尾的文件,而後須要使用 loader 進行轉換
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
}

編譯以前還須要安裝style-loadercss-loadernode

npm install --save-dev style-loader css-laoder

注意:webpack

  1. use屬性的值是一個使用loader名稱組成的數組,loader執行的順序是從後往前的,因爲loader執行有順序,故不能寫成這樣
use: ['css-loader', 'style-loader']
  1. 每一個loader均可以經過URL queryString的方式傳入參數,好比'css-loader?url'
  2. style-loader的原理:是將css的內容使用javascript的字符串存儲起來,在網頁執行javascript時經過DOM操做,動態地向HTML head標籤裏插入HTML style標籤。
  3. 配置loader的方式也能夠用Object來實現
use: ['style-loader', {
    loader: 'css-loader',
    options: {
        url: true
    }
}]

使用plugin

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

若是想要使用一個插件,咱們只須要require()它,而後把它添加到plugins數組中。咱們能夠在一個配置文件中由於不一樣的目的屢次使用用一個插件,所以咱們可使用new操做符來建立它的實列。github

上面使用loadercss加載到js中去,如今使用extract-text-webpack-plugin插件把bundle.js文件裏的css提取到單獨的文件中web

// 提取 css 的插件
const ExtractTextPlugin = require('extract-text-webpack-plugin')

module: {
    rules: [
        {
            // 用正則去匹配 .css 結尾的文件,而後須要使用 loader 進行轉換
            test: /\.css$/,
            loaders: ExtractTextPlugin.extract({
                //轉換 .css須要使用的 loader
                use: ['css-loader']
            })
        }
    ]
},
plugins: [
    //從 js 文件中提取出來的 .css 文件名稱
    new ExtractTextPlugin({
        filename: 'main.css'
    })
]

編譯以前須要安裝extract-text-webpack-pluginchrome

npm install --save-dev extract-text-webpack-plugin

執行webpack時報錯須要這樣安裝

npm install extract-text-webpack-plugin@next

DevServer

官方網站

安裝

npm install webpack-dev-server --save-dev

而後進行簡單的配置

devServer:{
    port: 3000,
    publicPath: "/dist"
}

而後用./node_modules/.bin/webpack-dev-server執行

資源壓縮

npm i uglifyJSPlugin-webpack-plugin --save-dev

配置文件

const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
plugins: [
    new UglifyJSPlugin({
        //默認是 false 須要手動開啓
        parallel: true
    })
]

或者

optimization: {
    minimizer: [new UglifyJsPlugin()],
},

按需加載

在代碼層面,webpack支持兩種方式進行異步模塊加載,一種是CommonJS形式的require.ensure,一種是ES6 Module形式的異步import()

異步加載的腳本不容許使用document.write,因此將module.js的代碼改爲console.log

export const log = function(){
    console.log('module.js loaded.')
}

編輯app.js,將module.js以異步的形式加載進來

import('./module.js').then(module =>{
    module.log()
}).catch(error => "An error occurred while loading the module")
document.write('app.js loaded.')

修改配置

module.exports = {
    mode: "production",
    entry: './app.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: "./dist"
    },
}

這裏咱們在output中添加了一個配置項publicPath,它是webpack中一個很重要有很容易引發迷惑的配置,當咱們的工程中有按需加載以及圖片和文件等外部資源時,就須要它來配置這些資源的路徑,不然頁面上就會報404,這裏咱們將publicPath配置爲相對於html的路徑,使按需加載的資源生產在dist目錄下,而且能正確地引用到它。

從新打包以後你會發現打包結果中多出一個1.mian.js,這裏面就是未來會被異步加載進來的內容。刷新頁面並查看chromenetwork標籤,能夠看到頁面會請求1.main.js。它並不來源於index.html中的引用,而是經過main.js在頁面插入了script標籤來將其引入的。

使用webpack的構建特性

2.0.0版本開始,webpack開始加入了更多的能夠優化構建過程的特性。

tree-shaking

在關於模塊的那一篇文章中咱們提到過,ES6 Module的模塊依賴解析是在代碼靜態分析過程當中進行的。換句話說,它能夠在代碼的編譯過程當中獲得依賴樹,而非運行時。利用這一點webpack提供tree-shaking功能,它能夠幫助咱們檢測工程中哪些模塊有從未被引用到的代碼,這些代碼不可能被執行到,所以也稱爲「死代碼」。經過tree-shakingwebpack能夠在打包過程當中去掉這些死代碼來減少最終的資源體積。

開啓tree-shaking特性很簡單,只要保證模塊遵循ES6 Module的形式定義便可,這意味着以前全部咱們的例子其實都是默認已經開啓了的。可是要注意若是在配置中使用了babel-preset-es2015或者babel-preset-env,則須要將其模塊依賴解析的特性關掉,如:

presets: [
    [env, {module: false}]
]

這裏咱們測試一下tree-shaking的功能,編輯module.js:

// module.js 
export const log = function() { 
    console.log('module.js loaded.'); 
} 

export const unusedFunc = function() { 
    console.log('not used'); 
}

打開頁面查看1.main.js的內容,應該能夠發現unusedFunc的代碼是不存在的,由於它沒有被別的模塊使用,屬於死代碼,在tree-shaking的過程當中被優化掉了。

tree-shaking最終的效果依賴於實際工程的代碼自己,在我對於實際工程的測試中,通常能夠將最終的體積減少3%~5%。整體來看,我認爲若是要使tree-shaking發揮真正的效果還要等幾年的時間,由於如今大多數的npm模塊仍是在使用CommonJS,所以享受不了這個特性帶來的優點。

scope-hoisting

scope-hoisting(做用域提高)是由webpack3提供的特性。在大型的工程中模塊引用的層級每每較深,這會產生比較長的引用鏈。scope-hoisting能夠將這種縱深的引用鏈拍平,使得模塊自己和其引用的其它模塊做用域處於同級。這樣的話能夠去掉一部分 webpack的附加代碼,減少資源體積,同時能夠提高代碼的執行效率。

目前若是要開啓scope-hoisting,須要引入它的一個內部插件:

module.exports = { 
    plugins: [ 
        new webpack.optimize.ModuleConcatenationPlugin() 
    ] 
}

scope-hoisting生效後會在bundle.js中看到相似下面的內容,你會發現log 的定義和調用是在同一個做用域下了:

// CONCATENATED MODULE: ./module.js 
const log = function() { 
    console.log('module.js loaded.'); 
} 

// CONCATENATED MODULE: ./app.js 
log();
相關文章
相關標籤/搜索