Skip to main content

[Webpack] webpack 入門

webpack 是個知名的打包工具,可以將我們所有的依賴工具(dependencies)、css、image 等進行打包,形成一個讓我們更快速進行開發的靜態範本(static assets)。此文章從 webpack 的官方文件與 Travery Media 的教學影片來了解與使用 webpack,其他常見的類似工具有 parcel, vite。

webpack 官網: https://webpack.js.org/

核心概念

透過以下概念,我們可以宏觀地了解 webpack 的使用方式,並打包成靜態網站資源。下面程式碼都寫在webpack.config.js內,用來設定 webpack。

Entry

進入點,決定我們要打包的檔案

module.exports = {
entry: "./path/to/my/entry/file.js",
};

Output

輸出點,決定我們打包完成的檔案要放在何處

const path = require("path");

module.exports = {
entry: "./path/to/my/entry/file.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "my-first-webpack.bundle.js",
},
};

Node.path

Loaders

載入器,由於 webpeck 原本只能打包 JavaScript 和 JSON 檔,透過 loaders 可以處理更多不同類型的檔案(image, css, sass 等),並打包在一起。 透過 loaders,我們可以處理 scss 變成 js 的 module,loaders 基本會有兩個屬性testuse

  1. test 決定什麼樣的檔案要被處理,通常以 regex 選擇
  2. use 決定用什麼樣的載入器(loader)
const path = require("path");

module.exports = {
output: {
filename: "my-first-webpack.bundle.js",
},
module: {
rules: {
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
},
};

Plugins

插件,可以被用在更廣泛的任務上,像是優化打包、插入環境變數等等,範例為帶入 HTML 範本。

html-webpack-plugin會製作出依據template屬性的範本,並自動帶入其他的打包模組,像是 js 檔。

const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack"); //to access built-in plugins

module.exports = {
module: {
rules: [{ test: /\.txt$/, use: "raw-loader" }],
},
plugins: [new HtmlWebpackPlugin({ template: "./src/index.html" })],
};

Mode

mode有三種,development, production or none,設置後會帶入 webpack 的內建優化。初始值為production

module.exports = {
mode: "production",
};

實作

接著,我們透過 Travery Media 的教學影片了解些常用的 webpack 的技巧與 config。

💻 Webpack Starter Repo: https://github.com/bradtraversy/webpack-starter

src & disc

src 資料夾存放我們的程式碼 disc 資料夾會放我們 build 出來的檔案,就像是在使用create-react-app裡面的npm run build會產生的 build 資料夾

npm 套件

我們主要是用在 development,開發模式中練習,故套件大多是安裝為devDependencies,使用npm i -D指令。

Dependencies are used for production or in testing environments. Whereas devDependencies are used for project development purposes only.

webpack

npm init -y // to create a Node.js project and skip the questions

npm i -D webpack, webpack-cli // -D means devDependencies

sass

npm i -D sass style-loader css-loader sass-loader

babel (JavaScript complier)

npm i -D babael-loader @bael/preset-env

https://babeljs.io/docs/en/index.html

webpack serve(可以開個 server 同步更新,跟 live server 很像)

npm i -D webpack-dev-server

webpack bundle 分析

npm i -D webpack-bundle-analyzer

scripts

要啟動 webpack 需要寫些指令在 package.json 裡面,build會產生靜態的 bundle,dev會開啟個 server 來呈現,需要指定devServer,而使用的是緩存,若是在啟動後刪除指定的資料夾,仍是可以執行。

  "scripts": {
"build": "webpack",
"dev": "webpack serve"
},

webpack config

整個 webpack.config.js,我們找比較特別的地方做紀錄,以下內容都寫在module.exports={}

entry, output

  mode: 'development',
entry: {
bundle: path.resolve(__dirname, 'src/index.js'),
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name][contenthash].js', /* name為"bundle",contenthash為雜湊,name可以參考entry的物件屬性,
* 最後會產出類似bundle24289f57aa2546d30093.js */
clean: true, // 清除上次的bundle
assetModuleFilename: '[name][ext]', // 靜態物件的名稱: name.extension(保持檔案原本的命名與副檔名)
},

產生 source-map

  devtool: 'source-map',
devServer
  devServer: {
static: {
directory: path.resolve(__dirname, 'dist'),
}, // where to serve
port: 3000,
open: true, // open automatically
hot: true, // hot reloading
compress: true, // enable gzip compression
historyApiFallback: true,
},

https://webpack.js.org/configuration/dev-server/#root

module
  module: {
rules: [
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.js$/,
exclude: /node_modules/, // 將node_modules排除在外
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource', // 預設的處理器,不用下載npm module
},
],
},

plugin

const HtmlWebpackPlugin = require('html-webpack-plugin')
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack App', // 可在template.html加入
filename: 'index.html', // 產出的黨名
template: 'src/template.html', // 模板html
}),
new BundleAnalyzerPlugin(), // 分析bundle,會跳一個bundle分析的網頁
],
template.html
<title><%= htmlWebpackPlugin.options.title %></title>

參考資料