Webpack In Action
目錄
P1.課程介紹
視訊教程
-
尚矽谷2020最新版Webpack5實戰教程(從入門到精通)
https://www.bilibili.com/video/BV1e7411j7T5?p=1
環境引數
- Node.js 10+
- Webpack 4.26+
預備技能
- 基本Node.js知識 和 Npm指令
- 熟悉ES6
P2.Webpack簡介
專案
初始化專案
cnpm init
在專案配置的步驟中
- package name輸入: webpack-first-demo,
- main:index.js
- 其它預設
安裝jquery
cnpm install jquery --save
建立基本檔案
- index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>webpack簡介</title> <link rel="stylesheet" href="./index.less"> </head> <body> <h1 id="title">Hello Webpack</h1> <script src="./index.js"></script> </body> </html>
- index.js
import $ from 'jquery';
$(function () {
$('#title').click(function () {
$('body').css('backgroundColor', 'deeppink');
});
})
- index.less
body,
html {
margin: 0;
padding: 0;
height: 100%;
background-color: pink;
}
#title{
color: #ffffff;
}
出現的問題
- 瀏覽器無法識別ES6的語法
至此在瀏覽器中瀏覽出現如下錯誤提示:
Uncaught SyntaxError: Cannot use import statement outside a module
原因是:
-
瀏覽器無法識別ES6的語法
-
瀏覽器無法識別
less
檔案
瀏覽器無法識別less
檔案,需要工具將less
檔案編譯成css
檔案 -
瀏覽器無法識別其它語言
瀏覽器無法識別其它語言(如jsx,vue),需要特定的工具轉化成js語法
構建工具
鑑於上節出現的問題,需要一個大的工具,把上面需要的一些小工具包裝來,webpack就是這樣一種構建工具
Webpack是什麼
Webpack 是一種前端資源構建工具,一個靜態模組打包器(module bunndler)。在Webpack看來,前端的所有資原始檔(js\json\css\img\less...)都會作為模組處理
它將根據模組的依賴關係進行靜態分析,打包生成對應的靜態資源(bundle)
入口檔案
一般Rect、Vue開發,通常會將一個檔案中引入整個專案需要的所有資源,如本例中的index.js
,該檔案稱之為入口檔案,在入口檔案引入檔案後
//引入js資源
import $ from 'jquery';
//引入樣式資源
import './index.less';
//引入圖片、字型等資源
//...
就會產生一條依賴鏈:
├── index.js/
├── index.js
├── index.less
├── jquery.js
Webpack將這些檔案組成一個chunk
(塊),然後編譯成瀏覽器能識別的js語法、css語法等,這個過程叫打包,然後輸出一個檔案,即bundle
├──入口檔案:index.js
├── index.js
├── index.less
├── jquery.js
├── ...
=> webpack
=> [chunk]
=> 編譯
├── xxx.js(ES6,Vue等) ->js
├── index.less ->css
=>輸出bundle.js
P3.Webpack的5個核心概念
https://www.webpackjs.com/concepts/
Entry
指示 webpack 應該使用哪個檔案為入口啟動開始打包,來作為構建其內部依賴圖的開始。
Output
告訴 webpack 打包後的資源bundles輸出到哪裡 ,以及如何命名這些檔案,預設值為 ./dist
。基本上,整個應用程式結構,都會被編譯到你指定的輸出路徑的資料夾中。你可以通過在配置中指定一個 output
欄位,來配置這些處理過程:
Loader
讓 webpack 能夠去處理那些非 JavaScript 檔案(webpack 自身只理解 JavaScript)
Plugins
外掛則可以用於執行範圍更廣的任務。外掛的範圍包括,從打包優化和壓縮,一直到重新定義環境中的變數。外掛介面功能極其強大,可以用來處理各種各樣的任務。
Mode
模式(Mode)指示webpack使用相應的模式配置
選項 | 描述 | 特點 |
---|---|---|
development | 會將process.NODE_ENV的值設定為development,啟用NamedChunksPlugin和NamedModulesPlugin | 能讓程式碼本地除錯執行的環境 |
production | 會將process.NODE_ENV設定為production,啟用ModuleConcatenation,NoEmitOnErrorsPlugin等 | 能讓程式碼優化上線執行的環境 |
P4 Webpack初體驗
建立專案
初始化專案
cnpm init
初始配置如下:
{
"name": "webpack-test",
"version": "1.0.0",
"description": "Webpack初體驗",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
安裝webpack和webpack-cli
這裡進行全域性安裝
cnpm install webpack webpack-cli -g
在新增到開發依賴
cnpm install webpack webpack-cli -D
這時package.json
檔案,新增如下開發依賴:
"devDependencies": {
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
}
建立基本檔案
專案結構
手動建立資料夾及其檔案:
- build
- src和 src/index.js
至此,專案結構如下:
/P04.Webpack初體驗
├── build
├── src
├── index.js
├── node_module
├── package.json
入口檔案
將入口檔案index.js
修改為:
/*
index.js: webpack入口起點檔案
1. 執行指令:
開發環境:webpack ./src/index.js -o ./build/built.js --mode=development
生成環境:webpack ./src/index.js -o ./build/built.js --mode=production
*/
function add(x, y) {
return x + y;
}
console.log(add(1,2));
執行開發指令
webpack ./src/index.js -o ./build/built.js --mode=development
結果提示:
Hash: b67461cf072bee7f194e
Version: webpack 4.43.0
Time: 142ms
Built at: 2020-07-13 1:18:15
Asset Size Chunks Chunk Names
built.js 4.03 KiB main [emitted] main
Entrypoint main = built.js
[./src/index.js] 240 bytes {main} [built]
- Hash:每次執行命令都產生一個唯一值
開發環境打包的輸出的檔案built.js
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./src/index.js");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("/*\r\nindex.js: webpack入口起點檔案\r\n\r\n1. 執行指令:\r\n 開發環境:webpack ./src/index.js -o ./build/built.js --mode=development\r\n 生成環境:\r\n\r\n*/\r\n\r\nfunction add(x, y) {\r\n return x + y;\r\n}\r\n\r\nconsole.log(add(1,2));\n\n//# sourceURL=webpack:///./src/index.js?");
/***/ })
/******/ });
執行生產環境指令
webpack ./src/index.js -o ./build/built.js --mode=production
資料結果:
Hash: 36798d9d9dd4621913cb
Version: webpack 4.43.0
Time: 357ms
Built at: 2020-07-13 1:26:56
Asset Size Chunks Chunk Names
built.js 946 bytes 0 [emitted] main
Entrypoint main = built.js
[0] ./src/index.js 300 bytes {0} [built]
生產環境打包的輸出的檔案built.js
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t){console.log(1+2)}]);
結論
- 生產環境生產的程式碼進行了優化壓縮
- 生成環境和開發環境將ES6模組化編譯成瀏覽器能識別的模組化
首頁index.html
建立首頁檔案build/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 引入打包後的資源 -->
<script src="./built.js"></script>
</body>
</html>
在瀏覽器中執行,在控制檯檢視輸出:
3
驗證Json檔案的打包
建立json檔案src\data.json
:
{
"name": "jack",
"age": 18
}
在src/index.js
引入 json檔案
import data from './data.json';
...
console.log(data);
再次執行build指令:
webpack ./src/index.js -o ./build/built.js --mode=development
輸出結果:
Hash: ef5d53549838e82e088b
Version: webpack 4.43.0
Time: 76ms
Built at: 2020-07-13 1:45:13
Asset Size Chunks Chunk Names
built.js 4.75 KiB main [emitted] main
Entrypoint main = built.js
[./src/data.json] 40 bytes {main} [built]
[./src/index.js] 333 bytes {main} [built]
檢視輸出檔案built.js
...
/***/ "./src/data.json":
/*!***********************!*\
!*** ./src/data.json ***!
\***********************/
/*! exports provided: name, age, default */
/***/ (function(module) {
eval("module.exports = JSON.parse(\"{\\\"name\\\":\\\"jack\\\",\\\"age\\\":18}\");\n\n//# sourceURL=webpack:///./src/data.json?");
...
將data.json
檔案也引入
瀏覽器控制檯輸出:
3
{name: "jack", age: 18}
name: "jack"
age: 18
...
結論
webpack可以處理Json檔案
驗證處理css檔案
建立css檔案src\index.css
:
body,
html {
margin: 0;
padding: 0;
height: 100%;
background-color: pink;
}
在src/index.js
引入 index.css
檔案
import './index.css';
...
再次執行build指令:
webpack ./src/index.js -o ./build/built.js --mode=development
輸出結果:
ERROR in ./src/index.css 2:5
Module parse failed: Unexpected token (2:5)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| body,
> html {
| margin: 0;
| padding: 0;
@ ./src/index.js 9:0-21
報錯了!!!,打包失敗了
結論
Webpack不能處理css/img等其它資源,
那如何打包css/img等其它資源,請看下一節
P5.打包樣式資源
打包CSS檔案
Webpack不能處理css資源,需要引入Loader
,
參考官方文件:https://www.webpackjs.com/concepts/loaders/
webpack的配置和引入Loader
在專案根目錄下建立webpack的配置檔案webpack.config.js
:
/*
檔名:webpack.config.js:webpack配置檔案
作 用:指示webpackg幹什麼活,當執行webpack指令時,會載入裡面的配置
所以的構建工具都是基於node.js 平臺執行的,模組化預設採用commonJs
*/
const {
resolve //用於拼接絕對路徑
} = require('path');
module.exports = {
//入口起點
entry: './src/index.js',
//輸出
output: {
//輸出檔名
filename: 'built.js',
//輸出路徑
//__dirname:nodejs的全域性變數,表示當前檔案所在目錄的絕對路徑
path: resolve(__dirname, 'build')
},
//Loader的配置
module: {
rules: [ //詳細的loader配置
// css-loader
{
//匹配那些檔案,這裡使用正則表示式進行匹配
test: /\.css$/,
//使用哪裡具體的loader,執行順序是從下往上
use: [
//建立style標籤,將js中的樣式資源插入,新增到head中生效
'style-loader',
//將css檔案變成commonJs模組載入到js中,裡面的內容是樣式字串
'css-loader'
]
},
]
},
// plugins的配置
plugins: [
],
//模式
mode: "development"
//mode:"production"
}
安裝style-loader和css-loader
cnpm install style-loader css-loader -D
"devDependencies": {
"css-loader": "^3.6.0",
"style-loader": "^1.2.1",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
}
執行webpack
在命令列輸入
webpack
輸出結果:
Hash: c210dbb4c83cb16ce67b
Version: webpack 4.43.0
Time: 459ms
Built at: 2020-07-13 3:08:03
Asset Size Chunks Chunk Names
built.js 17 KiB main [emitted] main
Entrypoint main = built.js
[./node_modules/[email protected]@css-loader/dist/cjs.js!./src/index.css] 363 bytes {main} [built]
[./src/index.css] 557 bytes {main} [built]
[./src/index.js] 255 bytes {main} [built]
+ 2 hidden modules
build\bulit.js
檔案中匯入的index.css
...
/***/ "./node_modules/[email protected]@css-loader/dist/cjs.js!./src/index.css":
/*!*******************************************************************************!*\
!*** ./node_modules/[email protected]@css-loader/dist/cjs.js!./src/index.css ***!
\*******************************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../node_modules/[email protected]@css-loader/dist/runtime/api.js */ \"./node_modules/[email protected]@css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"body,\\r\\nhtml {\\r\\n margin: 0;\\r\\n padding: 0;\\r\\n height: 100%;\\r\\n background-color: pink;\\r\\n}\\r\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/index.css?./node_modules/[email protected]@css-loader/dist/cjs.js");
/***/ }),
....
打包less資原始檔
建立src\index.less
檔案:
#title {
color: brown;
}
並在index.js
檔案中匯入
import './index.less';
less-loader
less-loader 將less檔案編譯成css檔案,
需要下載安裝:less和less-loader
cnpm install less --save-dev
cnpm install less-loader --save-dev
"devDependencies": {
...
"less": "^3.11.3",
"less-loader": "^6.2.0",
}
web配置檔案新增less-loader
//Loader的配置
module: {
rules: [
....
// 處理less檔案
{
//匹配那些檔案,這裡使用正則表示式進行匹配
test: /\.less$/,
//使用哪裡具體的loader,執行順序是從下往上
use: [
//建立style標籤,將js中的樣式資源插入,新增到head中生效
'style-loader',
//將css檔案變成commonJs模組載入到js中,裡面的內容是樣式字串
'css-loader',
//將less檔案編譯成css檔案
//需要下載less和less-loader
'less-loader'
]
},
]
},
...
### 其它檔案
- index.html
<body>
<h1 id="title">標題</h1>
<!-- 引入打包後的資源 -->
<script src="./built.js"></script>
</body>
執行webpack
在命令列輸入
webpack
輸出結果:
Hash: 607e9846a1cfaea095e5
Version: webpack 4.43.0
Time: 467ms
Built at: 2020-07-13 3:49:59
Asset Size Chunks Chunk Names
built.js 19.6 KiB main [emitted] main
Entrypoint main = built.js
[./node_modules/[email protected]@css-loader/dist/cjs.js!./node_modules/[email protected]@less-loader/dist/cjs.js!./src/index.less] 280 bytes {main} [built]
[./node_modules/[email protected]@css-loader/dist/cjs.js!./src/index.css] 363 bytes {main} [built]
[./src/index.css] 557 bytes {main} [built]
[./src/index.js] 275 bytes {main} [built]
[./src/index.less] 617 bytes {main} [built]