webpack2.x項目搭建入門實踐教程

1. 新建一個文件夾,命名為 webpack-cli , webpack-cli 就是你的項目名,項目名建議使用小寫字母,并且不帶空格,不能含有大寫字母.

2. 安裝 Webpack,Webpack 可以使用 npm 安裝.
使用終端在該文件夾中執行下述指令就可以完成安裝,由于網絡原因安裝過程可能需要一些時間。

//全局安裝
npm install -g webpack
//安裝到你的項目目錄
npm install --save-dev webpack
注:建議用淘寶鏡像的cnpm依賴包能下載的快一些

Webpack 可以全局安裝,也可以安裝到你的項目目錄.剛開始學習 Webpack 為了方便,建議同時全局安裝和安裝到你的項目目錄.

3. 在 webpack-cli 文件夾中創建一個 package.json 文件,這是一個標準的 npm 說明文件,里面蘊含了豐富的信息,包括當前項目的依賴模塊,自定義的腳本任務等等。在終端中使用 npm init 命令可以自動創建這個 package.json 文件.

npm init

輸入這個命令后,終端會問你一系列諸如項目名稱,項目版本,項目描述,入口文件,作者等信息,不過不用擔心,如果你不準備在 npm 中發布你的模塊,這些問題的答案都不重要,傻瓜式操作一路回車默認即可.這些信息今后都可以更改 package.json 來修改,所以不用擔心.

4. 在 webpack-cli 文件夾中創建兩個文件夾 src文件夾和 dist文件夾, src文件夾用來存放原始數據,例如: SASS 文件、LESS 文件、JavaScript 模塊等,dist 文件夾用來存放經過 Webpack 處理過的 src文件夾數據,這也是準備給瀏覽器讀取的數據,其中包括使用 Webpack 打包后的 js 文件等。在這里還需要在 dist 文件夾中創建 index.html 文件.在 src文件夾中創建 name.js 和 main.js 文件,此時項目結構如下圖所示:

7dd3450fc0d74c2129959f80083d61d.png

5.在 dist文件夾中的 index.html 文件只有最基礎的 html 代碼,它唯一的目的就是加載打包后的 js 文件 bundle.js.

// index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack-cli</title>
</head>
<body>
    <div id="root"></div>
    <script src="bundle.js"></script>
</body>
</html>

6. 在 src文件夾中的 name.js 只包括一個用來返回name信息的 html 元素的函數。

// name.js
module.exports = function(){
    var name = document.createElement('h1');
    name.textContent = "My name is MMhui";
    return name;
};

7. 在 src文件夾中的 main.js 用來把 name模塊(其實可以簡單的把它看作 name.js)返回的節點插入頁面。

// main.js
var name = require('./name.js');
document.querySelector('#root').appendChild(name());

Webpack 配置文件

Webpack 配置文件其實也是一個簡單的 JavaScript 模塊,可以把所有與項目構建相關的信息放在里面。在 webpack-cli 文件夾根目錄下新建一個名為 webpack.config.js 的文件,并在其中進行最簡單的配置.如下所示,它包含入口文件路徑和存放打包后文件的地方路徑。

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    }
};
注:__dirname 是 node.js 中的一個全局變量,它指向當前 js 文件所在的目錄.

現在只需要在終端里運行 webpack 命令就可以了,這條命令會自動參考 webpack.config.js 文件中的配置選項打包你的項目,輸出結果如下:



此時項目的 dist 文件夾下也會出現打包好的 bundle.js 文件.此時項目結構如下圖所示:



可以看出 webpack 同時編譯了 main.js 和 name.js,打開 src目錄下的 index.html 文件,就可以看到最終效果,如下圖:
利用 npm 更快捷的執行打包任務

通過 Webpack 配置文件和執行 webpack 命令其實是比較煩人且容易出錯的,不過值得慶幸的是 npm 可以引導任務執行,對其進行配置后可以使用簡單的 npm start 命令來代替這些繁瑣的命令。在 package.json 中對 npm 的腳本部分進行相關設置,相當于把 npm 的 start 命令指向 webpack 命令,設置方法如下:

// package.json
{
  "name": "webpack-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.8.1"
  }
}

執行 npm start 后命令行的輸出顯示:


現在只需要使用 npm start 就可以打包文件了.打開 dist 目錄下的 index.html 文件,看到的最終效果是不是與之前的一樣.

利用 Webpack 生成 Source Maps

簡單說,Source Maps 就是一個信息文件,里面儲存著位置信息。也就是說,轉換后的代碼的每一個位置,所對應的轉換前的位置.有了它,出錯的時候,除錯工具將直接顯示原始代碼,而不是轉換后的代碼。這無疑給開發者帶來了很大方便.為了方便調試可以利用 Webpack 生成 Source Maps.

在 Webpack 的配置文件中配置 Source Maps,需要配置 devtool,它有以下四種不同的配置選項,各有優缺點,描述如下:

1.source-map 在一個單獨的文件中產生一個完整且功能完全的文件。這個文件具有最方便調試的 Source Maps,但是這個文件會比較大,會減慢打包文件的構建速度.
2.cheap-module-source-map 在一個單獨的文件中生成一個不帶列映射的 Source Maps,不帶列映射能夠提高項目構建速度,但這也使得瀏覽器開發者工具只能對應到具體的行,不能對應到具體的列,會對調試造成不便.
3.eval-source-map 在同一個文件中生成干凈的完整的 Source Maps。這個選項可以在不影響構建速度的前提下生成完整的 Source Maps,但是對打包后輸出的 js 文件的執行具有性能和安全的隱患。不過在開發階段這是一個非常好的選項,但是在生產階段一定不要用這個選項.
4.cheap-module-eval-source-map 這是在打包文件時最快的生成 Source Maps 的方法,生成的Source Map 會和打包后的 js 文件同行顯示,沒有列映射,和 eval-source-map 選項具有相似的缺點,文件的執行具有性能和安全的隱患.

上述選項由上到下打包速度越來越快,不過同時也具有越來越多的負面作用,較快的構建速度的后果就是對打包的文件執行有一定影響。在學習階段以及在小到中型的項目上,eval-source-map是一個很好的選項,不過記得只在開發階段使用它.

編輯 webpack-cli 文件夾下的 webpack.config.js 文件配置 devtool 選項,生成 Source Maps 文件.配置 devtool 后的 webpack.config.js 文件如下:

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map' // 配置生成的source-map
};

執行 npm start 命令后就能生成對應的 Source Maps,終端輸出信息如下圖:



此時項目中 dist文件夾下也生成了名為 bundle.js.map 的 Source Maps 文件.此時項目結構如下圖所示:


使用 Webpack 構建本地服務器

想不想讓你的瀏覽器監測你修改的代碼,并自動刷新修改后的結果.其實 Webpack 提供一個可選的本地開發服務器,這個本地服務器基于 node.js 構建,可以實現你想要的這些功能,不過它是一個單獨的組件,在 Webpack 中進行配置之前需要單獨安裝它作為項目依賴.在終端中輸入下面的指令安裝對應組件.建議同時全局安裝和安裝到你的項目目錄.

//全局安裝
npm install -g webpack-dev-server
//安裝到你的項目目錄
npm install --save-dev webpack-dev-server

devserver 作為 Webpack 配置選項中的一項,具有以下配置選項

contentBase: 默認 webpack-dev-server 會為根文件夾提供本地服務器,如果想為另外一個目錄下的文件提供本地服務器,應該在這里設置其所在目錄(本例設置到“dist"文件夾下).
port: 設置默認監聽端口,如果省略,默認為"8080".
inline: 設置為 true,當源文件改變時會自動刷新頁面.
historyApiFallback: 在開發單頁應用時非常有用,它依賴于 HTML5 history API,如果設置為 true,所有的跳轉將指向 index.html.
open: 直接打開瀏覽器

編輯 webpack-cli 文件夾下的 webpack.config.js 文件配置以上選項.

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    }
};
在終端中輸入如下命令,構建本地服務器:
webpack-dev-server

終端輸出信息如下圖,表示 Webpack 構建的本地服務器已啟動.

瀏覽器自動打開 http://localhost:9000/ 就可以看到像之前一樣的頁面.

也可以使用 npm 更快捷的執行任務,編輯 webpack-cli 文件夾下的 package.json 文件 scripts 選項.

// package.json
{
    "name": "webpack-cli",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "start": "webpack",
        "dev": "webpack-dev-server --devtool eval --progress --content-base build"
    },
    "author": "",
    "license": "ISC"
}

在終端中執行 npm run dev 命令,輸出信息如下圖,一樣可以啟動的本地服務器.

按 Ctrl + C 即可退出本地服務器.

一切皆模塊

Webpack 有一個不可不說的優點,它把所有的文件都可以當做模塊處理,包括你的 JavaScript 代碼,也包括 CSS 和 fonts 以及圖片等等,只要通過合適的 Loaders,它們都可以被當做模塊被處理.

Loaders

webpack 可以使用 loader 來預處理文件。這允許你打包除 JavaScript 之外的任何靜態資源.通過使用不同的 loader,Webpack 通過調用外部的腳本或工具可以對任何靜態資源進行處理,比如說分析 JSON 文件并把它轉換為 JavaScript 文件,或者說把 ES6 / ES7 的 JS 文件轉換為現代瀏覽器可以識別的 JS 文件.對 React 開發而言,合適的 Loaders 可以把 React 的 JSX 文件轉換為 JS 文件.

Loaders 需要單獨安裝并且需要 在webpack.config.js 下的 modules 關鍵字下進行配置,Loaders 的配置選項包括以下幾方面:
test:一個匹配 Loaders 所處理的文件的拓展名的正則表達式(必須)
use:use: [ { loader: ['style-loader']}, { loader: ['css-loader'], options: { modules: true } } ]
include/exclude: 手動添加必須處理的文件/文件夾,或屏蔽不需要處理的文件/文件夾(可選)
loader:loader 的名稱(必須)
query:為 Loaders 提供額外的設置選項(可選)

繼續動手實踐,修改 src文件夾下的 name.js 文件,把問候消息放在一個單獨的 JSON 文件里,通過 loader 的使 name.js 可以讀取該 JSON 文件.

1. 在 src文件夾下創建 name.json 文件,并輸入如下代碼:

//name.json
{
    "name": "My name is MMhui"
}

2. 編輯 src文件夾下的 name.js 文件,修改后如下:

// name.js
var text = require('./name.json');
module.exports = function(){
    var name = document.createElement('h1');
    name.textContent = text.name;
    return name;
};

3. 安裝支持導入 JSON 文件的 json-loader .由于 webpack 2.× 默認支持導入 JSON 文件.如果你使用自定義文件擴展名,可能仍然需要使用此 loader.在終端中運行如下命令,安裝 json-loader 到你的項目中.

//安裝到你的項目中
npm install --save-dev json-loader

因為 json-loader 安裝到你的項目目錄里了,所以 webpack-cli項目下會新增一個 node_modules 文件夾用于存放安裝的 json-loader.此時的項目結構如下:

  1. 編輯 webpack.config.js 文件配置 modules 選項,添加 json-loader,編輯后的文件如下:
// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            }
        ]
    }
};

在終端中輸入 npm start 重新編譯打包,再在瀏覽器中打開 dist 文件夾下的 index.html 文件,如果看到和下圖一樣的,就說明 json-loader 配置成功了.

Babel

Babel 其實是一個編譯 JavaScript 的平臺,它的強大之處表現在可以通過編譯幫你達到以下目的:
把 ES6 / ES7 標準的 JavaScript 轉化為瀏覽器能夠解析的 ES5 標準的 JavaScript.
使用基于 JavaScript 進行了拓展的語言,比如 React 的 JSX.

Babel的安裝與配置

Babel 其實是幾個模塊化的包,其核心功能位于稱為 babel-core 的 npm 包中,不過 Webpack 把它們整合在一起使用,但是對于每一個你需要的功能或拓展,你都需要安裝單獨的包.用得最多的是解析 ES6 的 babel-preset-es2015 包和解析 JSX 的 babel-preset-react 包.

先來安裝這些依賴包,輸入如下命令,把這些依賴包安裝到你的項目中.

// 利用 npm 一次性安裝多個依賴模塊,模塊之間用空格隔開
npm install --save-dev babel-core babel-loader babel-preset-es2015

編輯 webpack.config.js 文件配置 module 選項,添加 Babel 配置,編輯后的文件如下:

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/, // 編譯打包時排除node_modules文件夾
                query: {
                    presets: ['es2015']
                }
            }
        ]
    }
};

使用 ES6 的語法,更新 src 文件夾下的 name.js 文件,修改后的代碼如下:

// Greeter.js
import text from './name.json';
let el = document.createElement('h1');
el.textContent = text.name + '改動了';
export default el;

使用 ES6 修改 src文件夾下的 main.js 文件,修改后的代碼如下:

// main.js
import name from './name.js';
document.querySelector('#root').appendChild(name);

在終端中運行 npm start 命令重新編譯打包,終端輸出信息如下:

在瀏覽器中打開 dist文件夾下的 index.html 文件,如果看到和下圖一樣的,就說明已經成功配置了 Babel.

Babel的配置選項

Babel 其實可以完全在 webpack.config.js 文件中進行配置,但是考慮到 babel 具有非常多的配置選項,在單一的 webpack.config.js 文件中進行配置往往使得這個文件顯得太復雜,因此一些開發者支持把 babel 的配置選項放在一個單獨的名為 ".babelrc" 的配置文件中。我們現在的 babel 的配置并不算復雜,不過之后我們會再加一些東西,因此現在我們就提取出相關部分,分兩個配置文件進行配置, Webpack 會自動調用 .babelrc 里的 babel 配置選項.

編輯 webpack.config.js 文件配置 modules 選項,添加 Babel 配置,編輯后的文件如下:

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            }
        ]
    }
};

webpack-cli 文件夾下新建 .babelrc 文件,添加如下代碼:

// .babelrc
{
    presets: ['es2015']
}

在終端中運行 npm start 命令重新編譯打包,終端輸出信息如下:

在瀏覽器中打開 dist文件夾下的 index.html 文件,如果看到和上次打開的html頁面一樣的,就說明已經成功配置了 Babel.

CSS

Webpack 提供兩個工具處理樣式表,css-loader 和 style-loader.

css-loader 使你能夠使用類似 @import 和 url(...) 的方法實現 require() 的功能
style-loader 將所有的計算后的樣式加入頁面中
二者組合在一起使你能夠把樣式表嵌入 Webpack 打包后的 JS 文件中。

先來安裝 css-loader, style-loader,輸入如下命令,把這些依賴包安裝到你的項目中.
npm install --save-dev style-loader css-loader

編輯 webpack.config.js 文件配置 module 選項,添加處理樣式表配置,編輯后的文件如下:

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                use: [
                    { loader: 'style-loader'},
                    {
                        loader: 'css-loader',
                        options: { modules: true }
                    }
                ]
            }
        ]
    }
};

接下來,在 src文件夾里創建一個名為 main.css 的文件,在文件中添加如下代碼,對一些元素設置樣式.

// main.css
html {
    box-sizing: border-box;
    -ms-text-size-adjust: 100%;
    -webkit-text-size-adjust: 100%;
}

html, body{
    width: 100%;
    height: 100%;
    background: #ccc;
}

Webpack 只有單一的入口,其它的模塊需要通過 import, require, url 等導入相關位置,為了讓 Webpack 能找到 main.css 文件,我們把它導入 src 文件夾下的 main.js 中.修改 src文件夾下的 main.js 文件,修改后的代碼如下:

// main.js
import name from './name.js';
import './main.css'; // 導入css文件
document.querySelector('#root').appendChild(name); 

在終端中運行 npm start 命令重新編譯打包,終端輸出信息如下:

在瀏覽器中打開 dist 文件夾下的 index.html 文件,如果看到和下圖一樣的,就說明已經配置成功了.

通常情況下,css 會和 js 打包到同一個文件中,并不會打包為一個單獨的 css 文件,不過通過合適的配置 Webpack 也可以把 css 打包為單獨的文件的。 不過這也只是 Webpack 把 css 當做模塊而已,繼續看一個真的 CSS 模塊的實踐.

CSS module

在過去的一些年里,JavaScript 通過一些新的語言特性、更好的工具、更好的實踐方法(比如說模塊化)發展得非常迅速。模塊使得開發者把復雜的代碼轉化為小的、干凈的、依賴聲明明確的單元,且基于優化工具,依賴管理和加載管理可以自動完成。

不過前端的另外一部分,CSS 的發展就相對慢一些,大多的樣式表卻依舊是巨大且充滿了全局類名,這使得維護和修改都非常困難和復雜。

CSS modules 的技術就能夠把 JS 的模塊化思想帶入 CSS 中來,通過 CSS 模塊,所有的類名,動畫名默認都只作用于當前模塊.

Webpack 從一開始就對 CSS 模塊化提供了支持,在 CSS loader 中進行配置后,你所需要做的一切就是把 modules 傳遞到需要的地方,然后就可以直接把 CSS 的類名傳遞到組件的代碼中,且這樣做只對當前組件有效,不必擔心在不同的模塊中具有相同的類名可能會造成的問題。

編輯 webpack.config.js 文件配置 modules 選項,添加處理樣式表配置,編輯后的文件如下:

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                use: [
                    { loader: 'style-loader'},
                    {
                        loader: 'css-loader?modules', // 此處多加了一個?modules
                        options: { modules: true }
                    }
                ]
            }
        ]
    }
};

接下來,在 src文件夾里創建一個名為 name.css 的文件,在文件中添加如下代碼,對一些元素設置樣式.

// name.css
.root{
display: flex;
background: #fff;
padding: 10px;
border: 4px solid #f00;
}
導入 .root 到 name.js 中,修改 src文件夾下的 name.js 文件,修改后的代碼如下:

// name.js
import text from './name.json';
import styles from './name.css'; // 導入.root到name.js中
let el = document.createElement('h1');
el.className = styles.root; // 導入.root到name.js中
el.textContent = text.name + '改動了';
export default el;

在終端中運行 npm start 命令重新編譯打包,終端輸出信息如下:

在瀏覽器中打開 dist文件夾下的 index.html 文件,如果看到和下圖一樣的,就說明已經配置成功了.

CSS modules 也是一個很大的主題,有興趣的話可以去官方文檔查看更多消息.下面兩篇文章也可以看看:

  1. CSS Modules 用法教程
  2. CSS Modules 詳解及 React 中實踐

CSS 預處理器

CSS 預處理器可以將 SASS、LESS 文件轉化為瀏覽器可識別的 CSS 文件,以下是常用的CSS 預處理器 loaders.
Less Loader
Sass Loader
Stylus Loader

其實也存在一個 CSS 的處理平臺 PostCSS,它可以幫助你的 CSS 實現更多的功能,可以看看<<PostCSS 是個什么鬼東西?>>.
舉例來說如何使用 PostCSS,我們使用 PostCSS 來為 CSS 代碼自動添加適應不同瀏覽器,不同版本的 CSS 前綴。

首先安裝 postcss-loader 和 autoprefixer(自動添加前綴的插件),安裝到你的項目中.
npm install --save-dev postcss-loader autoprefixer

編輯 webpack.config.js 文件配置 module 選項,添加 postcss-loader 處理樣式表配置,編輯后的文件如下:

// webpack.config.js
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                // 此處結構需要做一下修改
                use: [
                    'style-loader', 'css-loader?modules&importLoaders=1',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require('autoprefixer')
                            ]
                        }
                    }
                ]
            }
        ]
    }
};

在 webpack-cli 文件夾下新建 postcss.config.js 文件,添加如下代碼:

// postcss.config.js
module.exports = {
    plugins: [
        // 調用autoprefixer插件,還可以配置選項添加需要兼容的瀏覽器版本.
        require("autoprefixer")[{ browsers: ['ie>=8', '>1% in CN'] }]
    ]
}

現在你寫的樣式會自動根據 Can i use 里的數據添加不同前綴了.在終端中運行 npm start 命令重新編譯打包,終端輸出信息如下:

在瀏覽器中打開 dist 文件夾下的 index.html 文件,如果看到和下圖一樣的,就說明已經成功配置了 PostCSS.

插件(Plugins)

插件(Plugins)是用來拓展 Webpack 功能的,它會在整個構建過程中生效,執行相關的任務。 Loaders 和 Plugins 常常被弄混,但是他們其實是完全不同的東西,可以這么說,Loaders 是在打包構建過程中用來處理源文件的(JSX,Scss,Less..),一次處理一個;插件并不直接操作單個文件,它直接對整個構建過程其作用。

Webpack 有很多內置插件,同時也有很多第三方插件,可以讓我們完成更加豐富的功能。

使用插件的方法)使用插件的方法

要使用某個插件,我們需要通過 npm 安裝它,然后要做的就是在 Webpack 配置中的 Plugins 關鍵字部分添加該插件的一個實例.

編輯 webpack.config.js 文件配置 Plugins 選項,添加一個實現版權聲明的 BannerPlugin 插件,BannerPlugin 是內置插件不需要使用 npm 安裝.
編輯后的文件如下:

// webpack.config.js
var webpack = require('webpack');
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/dist/', // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './dist',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                // 此處結構需要做一下修改
                use: [
                    'style-loader', 'css-loader?modules&importLoaders=1',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require('autoprefixer')
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版權所有,侵權必究!!!')
    ]
};

在終端中運行 npm start 命令重新編譯打包,在瀏覽器中打開 dist文件夾下的 index.html 文件,如果看到和下圖一樣的,就說明已經成功配置了 BannerPlugin 插件.

常用插件

給大家推薦幾個常用的插件

HtmlWebpackPlugin

這個插件的作用是依據一個簡單的模板,幫你生成最終的 html 文件,這個文件中自動引用了你打包后的 JS 文件。每次編譯都在文件名中插入一個不同的哈希值。

安裝 HtmlWebpackPlugin 到你的項目中
npm install --save-dev html-webpack-plugin

在使用 HtmlWebpackPlugin 之前,需要對 webpack-cli 項目結構做一些改變.
1. 移除 dist文件夾.

2. 在 src目錄下,創建一個文件名為 index.html 模板文件,在編譯過程中,HtmlWebpackPlugin 插件會依據此模板生成最終的 html 頁面,會自動添加所依賴的 css、 js、favicon等文件.

index.html 模板文件代碼如下:
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack-cli</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

3. 在 webpack-cli 文件夾下新建一個 build 文件夾用來存放最終的輸出文件.

4. 編輯 webpack.config.js 文件配置 Plugins 選項,添加 HtmlWebpackPlugin 插件,修改 output 選項.編輯后的文件如下:

// webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/build/',    // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        contentBase: './build',
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                // 此處結構需要做一下修改
                use: [
                    'style-loader', 'css-loader?modules&importLoaders=1',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require('autoprefixer')
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins: [//在這個數組中new一個實例就可以了
        new webpack.BannerPlugin('版權所有,侵權必究!!!'),
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html' // new一個插件的實例,并傳入相關的參數
        })
    ]
};

此時項目結構如下圖所示:

在終端中運行 npm start 命令重新編譯打包,終端輸出信息如下:

此時項目結構已經發生改變,build 文件夾下存放了最終的輸出的文件,項目結構如下圖所示:

在瀏覽器中打開 build 文件夾下的 index.html 文件,如果看到和下圖一樣的,就說明已經成功配置了 HtmlWebpackPlugin 插件.

Hot Module Replacement

Hot Module Replacement(HMR)也是 Webpack 里很有用的一個插件,它允許你在修改組件代碼后,自動刷新實時預覽修改后的效果。 在 Webpack 中使用 HMR 也很簡單,只需要做兩項配置.

  1. 在 Webpack 配置文件中添加 HMR 插件
  2. 在 Webpack Dev Server 中添加 hot 參數

不過配置完這些后,JS 模塊其實還是不能自動熱加載的,還需要在你的 JS 模塊中執行一個 Webpack 提供的 API 才能實現熱加載,雖然這個 API 不難使用,但是如果是 React 模塊,使用我們已經熟悉的 Babel 可以更方便的實現功能熱加載。

整理下思路,具體實現方法如下

  1. Babel 和 Webpack 是獨立的工具,二者可以一起工作,二者都可以通過插件拓展功能.
  2. HMR 是一個 Webpack 插件,它讓你能瀏覽器中實時觀察模塊修改后的效果,但是如果你想讓它工作,需要對模塊進行額外的配額.
  3. Babel 有一個叫做 react-transform-hrm 的插件,可以在不同 React 模塊進行額外的配置下讓 HMR 正常工作.

編輯 webpack.config.js 文件配置 Plugins / devServer 選項,添加 Hot Module Replacement 插件.編輯后的文件如下:

// webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/build/',    // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true,
        hot: true // 熱加載
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                // 此處結構需要做一下修改
                use: [
                    'style-loader', 'css-loader?modules&importLoaders=1',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require('autoprefixer')
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins: [//在這個數組中new一個實例就可以了
        new webpack.BannerPlugin('版權所有,侵權必究!!!'),
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html' // new一個插件的實例,并傳入相關的參數
        }),
        new webpack.HotModuleReplacementPlugin() // 熱加載插件
    ]
};

編輯 webpack-cli 文件夾下的 package.json 文件 scripts 選項,添加 --hot 選項開啟代碼熱替換.

// package.json
{
  "name": "webpack-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack",
    "dev": "webpack-dev-server --devtool eval --progress --content-base build --hot"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^7.1.6",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-es2015": "^6.24.1",
    "css-loader": "^0.28.7",
    "html-webpack-plugin": "^2.30.1",
    "json-loader": "^0.5.7",
    "postcss-loader": "^2.0.8",
    "style-loader": "^0.19.0",
    "webpack": "^3.8.1",
    "webpack-dev-server": "^2.9.3"
  }
}

在終端中執行 npm run dev 命令,輸出信息如下圖,一樣可以啟動自動熱加載.瀏覽器打開界面如下圖:

產品階段的構建

我們已經使用 Webpack 構建了一個完整的開發環境.但是在產品階段,可能還需要對打包的文件進行額外的處理,比如說優化、壓縮、緩存以及分離 CSS 和 JS.

對于復雜的項目來說,需要復雜的配置,這時候分解配置文件為多個小的文件可以使得事情井井有條,以 webpack-cli 項目來說,我們在 webpack-cli 文件夾下創建一個名為 webpack.prod.config.js 的文件,在里面加上基本的配置代碼,如下:

// webpack.prod.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/build/',    // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                // 此處結構需要做一下修改
                use: [
                    'style-loader', 'css-loader?modules&importLoaders=1',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require('autoprefixer')
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html' // new一個插件的實例,并傳入相關的參數
        })
    ]
};

編輯 webpack-cli 文件夾下的 package.json 文件 scripts 選項,添加 build 選項,編輯后的文件如下:

// package.json
{
  "name": "webpack-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack",
    "dev": "webpack-dev-server --devtool eval --progress --content-base build --hot",
    "build": "webpack --config ./webpack.prod.config.js --progress"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^7.1.6",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-es2015": "^6.24.1",
    "css-loader": "^0.28.7",
    "html-webpack-plugin": "^2.30.1",
    "json-loader": "^0.5.7",
    "postcss-loader": "^2.0.8",
    "style-loader": "^0.19.0",
    "webpack": "^3.8.1",
    "webpack-dev-server": "^2.9.3"
  }
}

在終端中執行 npm run build 命令,輸出信息如下圖:

說明分解配置文件為多個小的文件成功了.

優化插件

Webpack 提供了一些在發布階段非常有用的優化插件,它們大多來自于 Webpack 社區,可以通過 npm 安裝,通過以下插件可以完成產品發布階段所需的功能.

OccurrenceOrderPlugin: 為組件分配 ID,通過這個插件 Webpack 可以分析和優先考慮使用最多的模塊,并為它們分配最小的 ID.
UglifyJsPlugin:壓縮JS代碼.
ExtractTextPlugin:分離 CSS 和 JS 文件.
我們來看看如何使用它們,OccurrenceOrderPlugin 和 UglifyJS plugins 都是內置插件,我們只需要安裝 ExtractTextPlugin 插件.

安裝 ExtractTextPlugin 插件
npm install --save-dev extract-text-webpack-plugin

編輯 webpack.config.js 文件配置 Plugins 選項,添加這三個插件,因為要分離 css 所以還要配置 module 下的 loaders 選項.編輯后的文件如下:

// webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/build/',    // 存放打包后文件的路徑
        filename: 'bundle.js'   // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true,
        hot: true // 熱加載
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                // 此處結構需要做一下修改
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: 'css-loader?modules!postcss-loader'
                })
            }
        ]
    },
    plugins: [//在這個數組中new一個實例就可以了
        new webpack.BannerPlugin('版權所有,侵權必究!!!'),
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html' // new一個插件的實例,并傳入相關的參數
        }),
        new webpack.HotModuleReplacementPlugin(), // 熱加載插件
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin('style.css')
    ]
};

在終端中執行 npm start 命令,輸出信息如下圖:

此時項目結構已經發生改變,build 文件夾下多出了抽離出來的 style.css 文件還有對應的 style.css.map 文件,項目結構如下圖所示:


如果你打開 build 文件夾下的 bundle.js 文件,就可以看到 bundle.js 文件內容已經被壓縮處理了.

說明這三個插件已經配置成功了.

緩存

為了加快加載速度,合理的利用緩存是必不可少的.使用緩存的最好方法是保證文件名和文件內容是匹配的.內容改變,名稱也相應改變.

Webpack 可以把一個哈希值添加到打包文件的文件名中,添加特殊的字符串混合體([name], [id] and [hash])到輸出文件名前,便于修改 BUG 以后,對應更新用戶本地的緩存文件.

編輯 webpack.config.js 文件修改 output / plugins 選項.編輯后的文件如下:

// webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
    entry: __dirname + '/src/main.js', // 入口文件路徑文件所在的目錄.
    output: {
        path: __dirname + '/build/',    // 存放打包后文件的路徑
        filename: '[name]-[hash].js'    // 打包后文件名
    },
    devtool: 'source-map', // 配置生成的source-map
    devServer: {
        port: '9000',
        inline: true,
        historyApiFallback: true,
        open: true,
        hot: true // 熱加載
    },
    module: {
        rules: [
            {
                test: /\.json$/,
                loader: 'json-loader'
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/ // 編譯打包時排除node_modules文件夾
            },
            {
                test: /\.css$/,
                // 此處結構需要做一下修改
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: 'css-loader?modules!postcss-loader'
                })
            }
        ]
    },
    plugins: [//在這個數組中new一個實例就可以了
        new webpack.BannerPlugin('版權所有,侵權必究!!!'),
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html' // new一個插件的實例,并傳入相關的參數
        }),
        new webpack.HotModuleReplacementPlugin(), // 熱加載插件
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin('[name]-[hash].css')
    ]
};

在終端中執行 npm start 命令,輸出信息如下圖:

此時項目 build 文件夾下的 main.css 和 main.js 文件都對應的加上了哈希值.項目結構如下圖所示:

如果你打開 build 文件夾下的 index.html 文件,就可以看到引用的 css、js 文件名也對應發生了改變,這樣修改 BUG 以后,也能對應更新用戶本地的緩存文件.

進階,永不止步

其實到這里我的這篇 Webpack 2.x 的入門實戰已經完結了!但這也只是個入門而已!在實際項目中運用還是不夠的,還有很多細節我并沒深入講,所以大家還想進階的話建議好好去看看 webpack-china 的文檔.
另外實戰項目 webpack-cli 的源碼,我已經放到 Github 上去了,歡迎大家提意見.
還有一點我覺得很重要,要學會看控制臺輸出信息,能夠看控制臺輸出信息解決的問題,就不要上 Google 搜了!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容