為什麼需要 webpack?
瀏覽器不支援 JavaScript 的 modules,所以我們透過 webpack 把寫好的 JavaScript 模組打包成一包,變成成瀏覽器可以看得懂的樣子。
index.js, utils.js → 經過 webpack 打包 → main.js
使用方法
在專案資料夾內安裝 webpack:
mkdir webpack-demo // 建立專案資料夾
cd webpack-demo // 切換目錄到專案資料夾
npm init -y // npm 初始化,建立 package.json
npm install webpack webpack-cli --save-dev // 安裝 webpack
通常開發者會把原始的檔案放在 src 資料夾,編譯過後的檔案放在 dist 資料夾,以方便管理。
執行 webpack 就可以進行編譯,預設會把 src 裡的檔案打包到 dist 內成名為 main.js 的檔案:
webpack
也可以在根目錄建立設定檔 webpack.config.js 來自定義路徑和要打包的模式,模式有兩種:
// production 的壓縮程度較高,檔案會變比較小,類似 uglify 過後的一串 JavaScript
// development 可讀性較高
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
};
可以在 package.json 建立 script:
"scripts": {
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
建立完 script 之後,輸入 npm run build 就可以執行 webpack 了:
npm run build
打包 npm 上別人第三方的 modules
webpack 強大之處在於它也可以把我們引入的第三方 modules 也一起打包進來。
使用 Loader 打包各種資源
除了打包 JavaScript 之外,webpack 把 modules 的概念延伸至更廣的範圍,各種資源都可以視為一個 module,所以我們也可以利用 webpack 幫我們打包圖片或 CSS。透過各種 loader 把資源載入 webpack,也可以順便做到 uglify JavaScript 或是 minify CSS 之類的編譯,以下會介紹一些常見的 loader 的使用。
css-loader
以打包 CSS 為例,在 webpack.config.js 加入 loader:
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
安裝 style.loader 和 css.loader:
npm install --save-dev css-loader style-loader
準備好 css 檔案:
body {
background: rgba(255, 0, 0, 0.3);
}
把 style.css 引入 index.js:
import css from './style.css';
import $ from 'jquery';
import { first } from './utils';
$(document).ready(()=>{
$('.btn').click(()=> {
alert(first('hello'));
})
})
打包成 main.js:
npm run build
在 index.html 引入 main.js:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="dist/main.js"></script>
<title>Document</title>
</head>
<body>
<button class="btn">click me</button>
</body>
</html>
這樣就可以把 style.css 也融入 main.js 一起讓瀏覽器讀到了,它的原理其實就只是透過 DOM 元素動態建立一個 區塊並把 .css 當成字串插入 區塊裡面:
其他 loader 的使用也很簡單,安裝完之後,在 webpack.config.js 設定 loader 就可以了!
babel-loader
安裝:
npm install -D babel-loader @babel/core @babel/preset-env
在 webpack.config.js 設定檔加入:
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
sass-loader
安裝:
npm install sass-loader sass webpack --save-dev
在 webpack.config.js 設定檔加入:
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
],
利用 Dev Server 自動化打包
dev server 是一套可以在檔案改變的時候自動重新打包的 plugin。
要使用 dev server,一樣先安裝起來:
npm install webpack-dev-server --save-dev
在設定檔中加入以下程式碼,告訴 dev server 最後編譯完的檔案放在哪裡:
devServer: {
contentBase: './dist',
},
在 package.json 加入 start 指令:
"scripts": {
"start": "webpack-dev-server --open",
}
暫時把 html 檔案也放在 dist 資料夾內,執行 npm run start:
npm run start
就會開始進入 dev server start 的狀態,之後 src 裡面的任何檔案有更改過,都會被 dev server 偵測到並自動重新打包:
使用 source map 看到原來程式碼的樣子
在 webpack.config.js 加入 source-map 程式碼:
module.exports = {
mode: 'development',
entry: {
app: './src/index.js',
},
devtool: 'inline-source-map',
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
在 debug 的時候,就可以在 chrome dev tool 溯源到真正的程式碼:
使用 HtmlWebpackPlugin
利用這個套件可以自動產生 HTML 檔案給我們的 webpack bundle 使用
安裝 HtmlWebpackPlugin:
npm install --save-dev html-webpack-plugin
在 webpack.config.js 加入 HtmlWebpackPlugin:
const HtmlWebpackPlugin = require('html-webpack-plugin');
並加上 plugins: [new HtmlWebpackPlugin()]
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js'
},
plugins: [new HtmlWebpackPlugin()]
};
自動產生的 HTML:
webpack 和 gulp 的差異
雖然這次介紹的 webpack 和上次介紹的 gulp 都有做到像是 babel, sass 轉 css 的功能,但它們本質上是不同的工具。
gulp 是一套 task manager,它的 task 可以有很多種,而不只侷限於 babel, sass, uglify js 這些,但它做不到像 webpack 那樣把所有的資源打包在一起。
而 webpack 的主要還是個打包工具,其目的是為了要讓瀏覽器能夠支援 module,只是我們在透過各種 loader 把資源載入給 webpack 打包成一包時,也可以進行 babel, sass 轉 css 之類的功能,所以才會覺得 gulp 和 webpack 很混淆。
簡單來說就是,gulp 可以做各種 tasks 但做不到打包,webpack 能做把各種資源打包,但做不到很多 gulp 才能做到的 tasks。