1 什麼是webpack webpack是一個模塊打包器,可以遞歸的構建一個依賴關係圖,其中包含每個程式需要的每個模塊,然後將所有模塊打包成一個或多個bundle。他和其他的工具最大的不同在於他支持code-splitting、模塊化(AMD,ESM,CommonJs)、全局分析。 bundle:b ...
1 什麼是webpack
webpack是一個模塊打包器,可以遞歸的構建一個依賴關係圖,其中包含每個程式需要的每個模塊,然後將所有模塊打包成一個或多個bundle。他和其他的工具最大的不同在於他支持code-splitting、模塊化(AMD,ESM,CommonJs)、全局分析。
bundle:bundle即由webpack打包出來的文件。
依賴關係:一個文件依賴於另一個文件,webpack就把這種關係視為依賴關係。所以webpack可以接受非代碼資源,並把它們當做依賴提供給應用程式。
2 主要概念
入口:entry指示webpack使用哪個文件作為構建依賴圖的開始。
出口: output指示webpack將打包好的bundles,如何命名以及輸出到哪裡。
loader:loader可以讓webpack如處理那些非JS文件,將起轉化為模塊(webpack只理解JS)
插件:plugins可以打包優化和壓縮等處理各種各樣的任務。
模式:mode設置為開發還是生產環境
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過 npm 安裝
const webpack = require('webpack'); // 用於訪問內置插件
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
],
mode:'production' || 'development'
};
3 詳細示例
3.1 入口 entry
module.exports = {
// 單個入口
entry: './path/to/my/entry/file.js'
// 為單個入口文件賦值名字
entry: {
main: './path/to/my/entry/file.js'
}
// 多文件多入口,一般用於分離 應用程式(app) 和 第三方庫(vendor) 入口
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
}
3.2 輸出 output
即使有多個入口文件,也只能規定一個輸出配置
module.exports = {
// 最低要求,filename和path
output:{
filename:'bundle.js',
path: '/home/proj/public/assets'
}
// 如果有多個入口文件,即生成多個單獨的"chunk",則要使用占位符來確保每個文件具有唯一的名字
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
3.3 模式 mode
module.exports = {
mode: 'production' //生產
mode: 'development' //開發
};
3.4 loader
由於webpack無法處理除了JS以外的文件,所以loader發揮了重要的作用。
loader用於對模塊的源代碼進行轉換,即將不同的語言轉化為js,或將內聯圖轉化為 data URL,也允許你直接在JS中import css文件,並且在bundle中引入這些依賴。
// npm install --save-dev css-loader
// npm install --save-dev ts-loader
//在webpack.config.js中配置
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' }
]
}
};
// 使用內聯方式配置
import Styles from 'style-loader!css-loader?modules!./styles.css';
// 通過 CLI 使用
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
3.5 插件 plugins
webpack 插件是一個具有 apply屬性的 JavaScript 對象,用來解決loader無法實現的其他事。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //通過 npm 安裝
const webpack = require('webpack'); //訪問內置的插件
module.exports = {
....
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
}
4 概念補充
4.1模塊 module
在模塊化編程中,開發者將程式分解成離散功能塊,並稱之為模塊。
模塊以各種方式表達他們的依賴關係:
- es2015 import 語句
- commonjs require() 語句
- AMD define 和 require 語句
- css/sass/less文件中的 @import 語句
- 樣式url(...)或HTML文件<img src=.../>中的圖片鏈接
4.2 模塊解析 module resolution
resolver是一個庫,用於幫助找到模塊的絕對路徑。當打包模塊時,webpack使用enhanced-resolve來解析文件路徑。
webpack中的解析規則:
// 已經取得文件的絕對路徑,不需要在做解析
import "C:\\Users\\me\\file";
// 在import/require給定的相對路徑,添加上下文路徑,轉化為絕對路徑
import "../src/file1";
// 模塊路徑
//(1)指定目錄,如果目錄具有擴展名,直接打包;如果沒有,查看resolve.extensions 的值,看看接受那些擴展名,如.js,.jsx
import "module";
//(2)指向文件夾
/*a.如果文件夾中包含 package.json 文件,則按照順序查找 resolve.mainFields 配置選項中指定的欄位。
並且 package.json 中的第一個這樣的欄位確定文件路徑。
b.如果 package.json 文件不存在或者 package.json 文件中的 main 欄位沒有返回一個有效路徑,則按照順序查找 resolve.mainFiles 配置選項中指定的文件名,看是否能在 import/require 目錄下匹配到一個存在的文件名。
c.文件擴展名通過 resolve.extensions 選項採用類似的方法進行解析。*/
import "module/lib/file";
4.3 Runtime 與 Manifest
在使用webpack構建的應用程式或站點中,有三種主要的代碼類型:
(1)你或你的團隊編寫的代碼;
(2)你的源碼會依賴的任何第三方的 library 或 vendor 代碼;
(3)webpack 的 runtime 和 mainfest,管理所有模塊的交互。
當打包之後,應用程式的目錄結構不復存在,webpack通過runtime與manifest管理各個模塊之間的聯繫與交互。
manifest保留著所有模塊的詳細要點(比如依賴於哪個模塊),將import或require語句都轉化為__webpack_require__方法,指向模塊標識符。
runtime根據manifest,查詢模塊標識符,實現模塊的載入和邏輯解析。
4.4 模塊熱替換 hot module replacement
模塊熱替換會在應用程式運行過程中替換、添加或刪除模塊,而無需重新載入整個頁面,主要通過以下方式來加快開發速度:
(1)保留在完全重新載入頁面時丟失的應用程式狀態;
(2)只更新變更的內容;
(3)像在瀏覽器調試器中更改樣式一樣快。
待理解之後補充:
(1)模塊路徑指向文件夾的查找方式;
(2)為何在使用緩存時,有些錶面上的內容沒有修改,計算出的哈希還是會改變。(文中原因::runtime和manifest的註入在每次構建都會發生變化);
(3)模塊熱替換的原理。