前言 - 閱讀《深入淺出webpack》一書實踐記錄一
目錄
- 安裝與使用
- Loader
- Plugin
- Devserver
安裝與使用
# npm i -D 是 npm install --save-dev 的簡寫,
--save 是指安裝模塊並保存到 package.json 的 devDependencies
# 安裝最新穩定版
npm i -D webpack
# 安裝指定版本
npm i -D webpack@<version>
# 安裝最新體驗版本
npm i -D webpack@beta
# 全局安裝
npm i -g webpack
下面通過 Webpack 構建一個基於 CommonJS 模塊化編寫的項目,該項目會使用JavaScript通過webpack編譯在網頁中顯示 Hello,Webpack。
創建一個HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!--引入 Webpack 輸出的 JavaScript 文件暫時命名 bundle.js -->
<script src="./dist/bundle.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
創建一個執行入口文件 main.js
var showText = require("./utils.js");
showText('Webpack');
main.js
裏邊的代碼很簡單,就是 require 導入一個模塊兒 utils.js
在commonJs模塊兒規範裏邊一個Js文件就相當於一個模塊兒,緊跟着就是調用這個模塊兒裏的函數;好,那麼此時我需要創建這個模塊兒文件utils.js
創建utils.js
// 操作 DOM 元素,把 content 顯示到網頁上
function showText(content) {
window.document.getElementById('app').innerText = 'Hello,' + content;
}
// 通過 CommonJS 規範導出 show 函數
module.exports = showText;
內容也很簡單就是一個函數 showText
,函數體就是在頁面顯示一段文本,緊跟着後邊就是導出這個函數。
好,入口文件以及執行的操作都有了,接下來我們需要一個webpack配置文件,緊接着,我們再創建一個webpack.config.js 文件
創建webpack.config.js
const path = require('path');
module.exports = {
entry: './main.js', // 入口文件,很重要,運行webpack構建唯一執行的文件
output: {
// 把所有依賴的模塊合併輸出到一個 bundle.js 文件
filename: 'bundle.js',
// 輸出文件都放到 dist 目錄下
// __dirname 只當前指向目錄
path: path.resolve(__dirname, './dist'),
}
};
內容其實也很少啊,我們簡單分析一下,path
基於node模塊的path
模塊兒,主要就是路徑(顧名思義啊),然後就是導出一個對象,這個對象裏邊包含了入口文件和出口文件配置;具體的解釋都寫在代碼註釋了。
截至到這裏,我們的準備文件都已經就緒了,目錄暫時如下:
webpack // 工程目錄
index.html
main.js
utils.js
webpack.config.js
看到這裏,小夥伴們是不是感覺還差點什麼,對,package.json 文件,那麼我們初始化一下
npm install
, 會發現命令行裏會讓我們填寫一些東西,例如:webpack項目名字,作者,版本,入口文件等等。我們一一確認一下就好。
package.json 文件,我們需要在 scripts 對象裏新增一條執行命令,執行我們的
webpack 配置文件,也就是 webpack.config.js
文件
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "HiSen",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// 新增命令
"build":"webpack --config webpack.config.js"
},
"author": "",
"license": "ISC"
}
準備就緒了,我們安裝 webpack npm install -D webpack
, 然後執行我們的webpack構建命令 npm run build
其實就是執行的 "webpack --config webpack.config.js"
看上邊的scripts對象。結果不盡人意啊(如下圖示),還讓我們安裝 webpack-cli
理由既然是作爲單獨的包提供,好吧,照着來吧。
這裏有一個小插曲,選擇 yes 安裝居然會報錯,我沒有去查看到底是因爲什麼啊,我直接自己命令裝了一下
好了,這一下算是全部文件準備就緒了,此時我們的目錄和package.json
文件都發生了一點點小小的改變;如下:
webpack // 工程目錄
index.html
main.js
utils.js
webpack.config.js
package.json
node_modules
目錄在安裝webpack的時候會自動生成一個依賴文件,node_modules
package.json
文件 devDependencies
對象也增加了我們安裝的 webpack
和 webpack-cli
;
最後,我們來嘗試構建打包一下:npm run build
恭喜你 ,結果很明顯,成功了,我們簡單的實現了一個webpack構建打包的實例。
代碼結構目錄
webpack // 工程目錄
dist // 構建生成目錄
bundle.js
index.html
main.js
utils.js
webpack.config.js
package.json
node_modules
打開本地的HTML就可以看到,我們的頁面,可能會遇到一個小小的錯誤
Cannot set property 'innerText' of null
因爲JavaScript運行時,id="app"的那個div元素可能還沒解析和加載,只需把整個搬到前面即可,就像這樣:
最後結果:
Loader
很重的一個知識點,接下來我們能創建一個css文件 main.css
,然後同樣在我們的入口文件main.js
文件引入,結果如下:
main.css
文件內容
#app{
text-align: center;
color:red;
}
main.js
導入
require("./main.css"); // 導入main.css 文件
var showText = require("./utils.js");
showText('Webpack');
顯然這樣直接構建,Webpack 構建是會報錯的,因爲 Webpack 不原生支持解析 CSS 文件。要支持非 JavaScript 類型的文件,需要使用 Webpack 的 Loader 機制。所以我們修改webpack.config.js
文件,添加 Loader
配置(Loader 可以理解爲是文件解析器,解析類似 css,less,scss等)
module.exports = {
entry: './main.js', // 入口文件
output: {
// 把所有依賴的模塊合併輸出到一個 bundle.js 文件
filename: 'bundle.js',
// 輸出文件都放到 dist 目錄下
// __dirname 只當前指向目錄
path: path.resolve(__dirname, './dist'),
},
// 添加如下配置
module: {
rules: [
{
test: /\.css$/, // 用正則去匹配要用該 loader 轉換的 CSS 文件
use: ['style-loader', 'css-loader'] // 注意這裏順序不能錯
}
]
}
};
user 還有另外一種寫法,數組對象形式
use: [
'style-loader',
{
loader:'css-loader',
options:{
minimize:true, // minimize 告訴 css-loader 要開啓 CSS 壓縮。
}
}
]
配置裏的 module.rules 數組配置了一組規則,告訴 Webpack 在遇到哪些文件時使用哪些 Loader 去加載和轉換。
這裏的配置告訴 Webpack 在遇到以 .css 結尾的文件時先使用 css-loader 讀取 CSS 文件,再交給 style-loader 把 CSS 內容注入到 JavaScript 裏。
注意:
use 屬性的值需要是一個由 Loader 名稱組成的數組,Loader 的執行順序是由後到前的; 每一個 Loader 都可以通過 URL querystring (或者數組對象)的方式傳入參數。
好,接下來,我們來實踐一下,在構建之前,首先需要安裝 Loader,在這裏使用到了 style-loader,css-loader
,安裝一下
npm i -D style-loader css-loader
package.json
文件會顯示出來,後續大家請自己關注,我就不貼圖了。
效果如下
你會發現 bundle.js 文件被更新了,裏面注入了在 main.css 中寫的 CSS,而不是會額外生成一個 CSS 文件。 但是重新刷新 index.html 網頁時將會發現 Hello,Webpack 居中了,樣式生效了! 也許你會對此感到奇怪,第一次看到 CSS 被寫在了 JavaScript 裏!這其實都是 style-loader 的功勞,它的工作原理大概是把 CSS 內容用 JavaScript 裏的字符串存儲起來, 在網頁執行 JavaScript 時通過 DOM 操作動態地往 HTML head 標籤裏插入 HTML style 標籤。 也許你認爲這樣做會導致 JavaScript 文件變大並導致加載網頁時間變長,想讓 Webpack 單獨輸出 CSS 文件。接着往下看
Plugin
首先我們需要下載插件 extract-text-webpack-plugin
npm i -D extract-text-webpack-plugin
然後直接看向 webpack.config.js
配置文件,進行如下配置:
1,引入extract-text-webpack-plugin
插件, 作用是提取出 JavaScript 代碼裏的 CSS 到一個單獨的文件
2,module
裏添加 plugin
數組,通過插件的 filename
屬性,告訴插件輸出的 CSS 文件名稱是通過 [name]_[contenthash:8].css
字符串模版生成的,裏面的[name]
代表文件名稱,[contenthash:8]
代表根據文件內容算出的8位 hash 值,
3,修改rules
裏邊use
,使用ExtractTextPlugin
插件轉換 css-loader
,這裏不需要再使用style-loader
解析了。
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); // 引入 plugin 插件
module.exports = {
entry: './main.js', // 入口文件
output: {
// 把所有依賴的模塊合併輸出到一個 bundle.js 文件
filename: 'bundle.js',
// 輸出文件都放到 dist 目錄下
// __dirname 只當前指向目錄
path: path.resolve(__dirname, './dist'),
},
// 添加如下配置
module: {
rules: [
{
// 用正則去匹配要用該 loader 轉換的 CSS 文件
test: /\.css$/,
// use: ['style-loader', 'css-loader'],
use: ExtractTextPlugin.extract({
// 轉換 .css 文件需要使用的 Loader
use: ['css-loader']
}),
}
]
},
plugins: [
new ExtractTextPlugin({
// 從 .js 文件中提取出來的 .css 文件的名稱
filename: `[name]_[contenthash:8].css`,
}),
]
};
以上修改完成後,我們開始構建,索嘎,成功的構建出來了,如果發現報錯,請檢查webpack
版本和ExtractTextPlugin
版本是否匹配。
構建出來的 dist
目錄如下:
dist
bundle.js // js 裏邊也不含有 css 樣式代碼了
main_69bba57c.css // 而這個css文件就是我們的 main.css 文件
DevServer
前面的幾節只是讓 Webpack 正常運行起來了,但在實際開發中你可能會需要:
1,提供 HTTP 服務而不是使用本地文件預覽;
2,監聽文件的變化並自動刷新網頁,做到實時預覽;
3,支持 Source Map,以方便調試。
當然這些 webpack
都爲你想好了,DevServer
會啓動一個 HTTP 服務器用於服務網頁請求,同時會幫助啓動 Webpack
,並接收 Webpack
發出的文件更變信號,通過 WebSocket 協議自動刷新網頁做到實時預覽。
好了,我們實踐一下,安裝 webpack-dev-server
這裏有版本兼容問題,我用的是2.9.4,[email protected],大家需要注意以下。
npm i -D webpack-dev-server
運行命令 webpack-dev-serve
, 如下運行成功,此時有一個地方,注意看,第三行,四行
這意味着 DevServer 啓動的 HTTP 服務器監聽在 http://localhost:8081/ ,DevServer 啓動後會一直駐留在後臺保持運行。
細心的小夥伴已經發現了問題,我們的打開 http://localhost:8081/
發現網頁內容沒錯,可是樣式卻沒了,而且 ./dist/bundle.js
加載404了;原因是 DevServer
會把 Webpack
構建出的文件保存在內存中,在要訪問輸出的文件時,必須通過HTTP
服務訪問。 由於DevServer
不會理會 webpack.config.js
裏配置的output.path
屬性,所以正確的 index.html 應該修改爲:
<link rel="stylesheet" href="main_69bba57c.css">
<script src="bundle.js"></script>
然後大家再嘗試着修改任何文件,會發現,猶如熱更新一樣,隨着修改,終端和網頁都在隨之刷新。
好了,第一章節就到這了,我們下章見。