一、Webpack基本配置及使用
1、安裝本地Webpack
webapck webpack-cli -D
// -D 表示上線不需要打這個包
// 初始化一下,記錄安裝的依賴
yarn init -y
// 5.2支持的npx語法可以直接執(zhí)行webpack
// 默認(rèn)去找node_modules下面的bin文件里面的webpack.cmd
npx webpack
2、 Webpack可以0配置
打包工具 -> 輸出后的結(jié)果(js模塊)
打包 -> 支持js模塊化
// 執(zhí)行這行命令,即可打包出一個main.js文件
npx webpack
提示需要配置mode
3、手動配置Webpack
1. 簡單示例
默認(rèn)配置文件的名字:webpack.config.js
// webpack 是 node 寫出來的 所以要用node的寫法來運行
const path = require('path');
// 這是一個導(dǎo)出的配置文件
module.exports = {
mode: 'development', // 模式(兩種):production development
entry: './src/index.js', // 入口
output: { // 出口
filename: 'bundle.js', // 打包后的文件名
path: path.resolve(__dirname, 'dist') // 路徑(必須是一個絕對路徑),__dirname不加也可以
}
}
// 結(jié)果:會在根目錄下有一個 dist/bundle.js 文件
// 可以在瀏覽器環(huán)境中運行即可
簡易示例文件
// src/index.js
let str = require('./a.js');
console.log(str);
// src/a.js
module.exports = 'hello';
打包后的結(jié)果
// dist/bundle.js
(() => {
var __webpack_modules__ = {
"./src/a.js": // key -> 模塊的路徑
(module) => { // value -> 函數(shù)
eval(
"module.exports = 'hello'\n\n//# sourceURL=webpack://practise/./src/a.js?"
);
},
"./src/index.js":
(
__unused_webpack_module,
__unused_webpack_exports,
__webpack_require__
) => {
eval(
'let str = __webpack_require__("./src/a.js")\r\n\r\nconsole.log(str)\n\n//# sourceURL=webpack://practise/./src/index.js?'
);
},
};
// 定義了一個緩存[如果模塊加載完了,不需要再次加載,從緩存中取出即可]
var __webpack_module_cache__ = {};
// 配置實現(xiàn)require方法(因為require無法在瀏覽器中運行)
function __webpack_require__(moduleId) {
var cachedModule = __webpack_module_cache__[moduleId];
// 檢查模塊在不在緩存中,如果在緩存中,直接返回模塊
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// 安裝一個模塊[key: Object]
var module = (__webpack_module_cache__[moduleId] = {
exports: {},
});
// 通過key找到對應(yīng)函數(shù)并執(zhí)行
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
// 返回對應(yīng)的module.exports即可
return module.exports;
}
var __webpack_exports__ = __webpack_require__("./src/index.js"); // './src/index.js': 入口模塊
})();
2. 修改配置文件名
如果想要將配置文件名修改,如:webpack.config.my.js ,此時打包拋出異常

但是我們希望可以找到我們的配置文件。可以這樣做:
npx webpack --config webpack.config.my.js
但是為了更方便,我們可以在 package.json 中進行配置:
{
//...
"scripts": {
"build": "webpack --config webpack.config.my.js"
}
//...
}
執(zhí)行 npm run build 或yarn build 即可,其他類似。
但是下面這樣寫是需要注意的:
"scripts": {
"build": "webpack"
}
// 它并不是一個參數(shù),不會識別config后面的內(nèi)容
npm run build --config webpack.config.my.js
yarn build --config webpack.config.my.js // yarn命令是可以的
// 如果一定要這樣寫,可以使用下面這種方式
npm run build -- --config webpack.config.my.js
3. 本地開發(fā)服務(wù)(通過ip訪問)[webpack-dev-server]
webpack-dev-server
// 可通過 npx webpack-dev-server 開啟,也可配置腳本
// package.json
"scripts": {
"dev": "webpack-dev-server"
}
// webpack.config.js
module.exports = {
// ...
devServer: { // 開發(fā)服務(wù)器的配置
port: 3000, // 端口號配置
progress: true, // 可以看到打包進度條
contentBase: './dist', // 指向打包目錄,希望以這個目錄作為靜態(tài)服務(wù)
compress: true // 啟動gzip壓縮
}
// ...
}
由于高版本的 webpack 與 webpack-dev-server 的兼容問題,如果不成功,可以修改腳本如下:
// package.json
"scripts": {
"dev": "webpack serve"
}
4. 使用模板自動插入腳本[html-webpack-plugin]
html-webpack-plugin
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 這是一個類
module.exports = {
// ...
output: { // 出口
filename: 'bundle.[hash].js', // 打包后的文件名,這里也加個hash避免緩存
// filename: 'bundle.[hash:8].js', // 打包后的文件名,這里也加個hash避免緩存:hash只要8位
path: path.resolve(__dirname, 'dist') // 路徑(必須是一個絕對路徑),__dirname不加也可以
},
plugins: [ // 數(shù)組:放著所有的webpack插件
new HtmlWebpackPlugin({
template: './src/index.html', // 模板
filename: 'index.html', // 打包后的文件名
minify: {
removeAttributeQuotes: true, // 刪除屬性雙引號
collapseWhitespace: true // 折疊空行,變成一行
},
hash: true // 避免緩存問題,加上hash戳
})
]
// ...
}
5. 樣式處理
Webpack默認(rèn)只支持 JS 模塊,所以對于 CSS ,需要特殊處理。
yarn add css-loader style-loader -D
yarn add less less-loader -D
...
// webpack.config.js
module.exports = {
// ...
module: { // 模塊
rules: [ // 規(guī)則
{
// css-loader: 解析 @import 這種語法的
// style-loader: 把css插入到head的標(biāo)簽中
// loader特點:希望單一
// loader的用法:字符串只用一個loader
// 多個loader需要數(shù)組
// loader的順序:默認(rèn)從右向左、從下到上執(zhí)行
// loader還可以寫成對象的形式
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {
// insertAt: 'top' // css的樣式插入到頂部,避免head中的style被覆蓋
// insertAt 已廢棄
insert: () => {
}
}
},
'css-loader'
]
},
{
// 處理less文件
// 還有 sass stylus, 類似的處理方式
// sass -> node-sass sass-loader
// stylus -> stylus-loader
test: /\.less$/,
use: [
{
loader: 'style-loader',
options: {
// insertAt: 'top' // css的樣式插入到頂部,避免head中的style被覆蓋
// insertAt 已廢棄
insert: () => {
}
}
},
'css-loader', // 解析 @import 這種語法的
'less-loader' // less -> css
]
}
]
}
// ...
}
1. CSS抽離成單獨的文件
mini-css-extract-plugin
yarn add mini-css-extract-plugin -D
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [ // 數(shù)組:放著所有的webpack插件
new MiniCssExtractPlugin({
filename: 'main.css' // 抽離css的文件名
})
],
module: { // 模塊
rules: [ // 規(guī)則
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader', // 解析 @import 這種語法的
'less-loader' // less -> css
]
}
]
}
}
2. 自動添加瀏覽器前綴
yarn add postcss-loader autoprefixer -D
配置如下:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader'
]
}
]
}
}
但是我們要告訴webpack我們要使用 autoprefixer, 所以需要在根目錄(webpack.config.js 同級目錄)新建一個 postcss.config.js 文件:
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
如果以上未生效,在 package.json 文件中增加如下配置:
// package.json
{
// ...
"browserslist": [
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
]
// ...
}
3. CSS 壓縮
optimize-css-assets-webpack-plugin
配置如下:
// webpack.config.js
module.exports = {
// ...
optimization: { // 優(yōu)化項
minimizer: [
new OptimizeCssAssetsWebpackPlugin()
]
}
// ...
}
但是,使用了這個插件,會導(dǎo)致 js 不會被壓縮了,所以必須配合使用另外一個插件:
uglifyjs-webpack-plugin
// webpack.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
// ...
optimization: { // 優(yōu)化項
minimizer: [
new UglifyjsWebpackPlugin({
cache: true, // 是否使用緩存
parallel: true, // 是否是并發(fā)打包,可以同時打多個
sourceMap: true // 壓縮完js,ES6變?yōu)镋S6,需要一個源碼映射
}),
new OptimizeCssAssetsWebpackPlugin()
]
},
// ...
}
6. 轉(zhuǎn)換ES6語法
1. 基礎(chǔ)語法
yarn add babel-loader @babel/core @babel/preset-env -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6轉(zhuǎn)換為es5
options: {
presets: [
'@babel/preset-env' // 把es6轉(zhuǎn)換為es5的模塊
]
}
}
}
]
}
// ...
}
2. class
yarn add @babel/plugin-proposal-class-properties -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6轉(zhuǎn)換為es5
options: {
presets: [
'@babel/preset-env' // 把es6轉(zhuǎn)換為es5的模塊
],
plugins: [
'@babel/plugin-proposal-class-properties'
]
}
}
}
]
}
// ...
}
3. 裝飾器
yarn add @babel/plugin-proposal-decorators -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6轉(zhuǎn)換為es5
options: {
presets: [
'@babel/preset-env' // 把es6轉(zhuǎn)換為es5的模塊
],
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
}
}
]
}
// ...
}
4. JS語法及校驗
代碼運行時的一個包。
1. generator、promise 等的處理
yarn add @babel/plugin-transform-runtime -D
yarn add @babel/runtime
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6轉(zhuǎn)換為es5
options: {
presets: [
'@babel/preset-env' // 把es6轉(zhuǎn)換為es5的模塊
],
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
"@babel/plugin-transform-runtime"
]
}
},
include: path.resolve(__dirname, 'src'), // 包括,只要這個目錄下的
exclude: /node_modules/ // 排除這個目錄下面的
}
]
}
// ...
}
2. 實例方法不會被解析的處理
如 includes。
yarn add @babel/polyfill
3. JS語法校驗
yarn add eslint eslint-loader -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/, // 可以同時寫多個
use: {
loader: 'eslint-loader',
options: {
enforce: 'pre' // previous 強制在其他的loader之前執(zhí)行
}
}
},
{
test: /\.js$/,
// ...
}
]
}
// ...
}
7. 全局變量的引入(三種方式)
1. expose-loader
2. ProvidePlugin
3. 引入不打包(externals)
expose-loader
暴露全局的loader 內(nèi)聯(lián)的loader
yarn add expose-loader
用法:
// 1、 內(nèi)聯(lián)的方式
import $ from 'expose-loader?$!jquery'
console.log(window.$)
// 2、配置到webpack.config.js中的方式,并且引入使用
import $ from 'jquery'
// ----
module.exports = {
// ...
module: {
rules: [
{
test: require.resolve('jquery'),
use: 'expose-loader?$'
}
]
}
// ...
}
// 3、配置到webpack.config.js中的方式
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.ProvidePlugin({ // 在每個模塊中都注入 $。 [但是這樣 window.$ 拿不到]
$: 'jquery'
})
]
// ...
}
注意
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
externals: { // 意義:這個模塊是外部引入的,不需要打包
jquery: '$'
}
// ...
}
8. 圖片處理
1. 在JS中創(chuàng)建圖片引入(new Image())
yarn add file-loader -D
file-loader 默認(rèn)會在內(nèi)部生成一張圖片到打包后的目錄下,把生成的圖片的名字返回回來
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: 'file-loader'
}
]
}
// ...
}
2. 在CSS中引入(background('url'))
css-loader 已支持
3. 在html中引入(<img src="">)
yarn add html-withimg-loader -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.html$/,
use: 'html-withimg-loader'
}
]
}
// ...
}
4. base64轉(zhuǎn)換圖片
當(dāng)圖片大于某個限制大小時,使用file-loader產(chǎn)出一個文件。但是小于這個限制值的時候,可以用base64來轉(zhuǎn)化。
可以不用發(fā)起http請求去加載圖片。
yarn add url-loader -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
limit: 100 * 1024 // 圖片小于100k,就使用base64,否則用file-loader產(chǎn)生真實的圖片
}
}
}
]
}
// ...
}
9. 打包文件分類
1. 圖片目錄
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
limit: 1,
outputPath: 'img/' // 打包到打包路徑下的 img 目錄中
}
}
}
]
}
// ...
}
但是引用是希望引用域名下這個目錄對應(yīng)的文件:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 這是一個類
module.exports = {
// ...
output: { // 出口
filename: 'bundle.[hash:8].js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://127.0.0.1:5500/dist' // 加這樣一個域名
}
// ...
}
但是只想給圖片加上這個域名,就可以這樣做:
// webpack.config.js
module.exports = {
// ...
output: { // 出口
filename: 'bundle.[hash:8].js',
path: path.resolve(__dirname, 'dist')
}
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
limit: 1,
outputPath: 'img/',
// 加這樣一個域名,并且需要拼接上上面的輸出目錄
publicPath: 'http://127.0.0.1:5500/dist/img'
}
}
}
]
}
// ...
}
2. 樣式目錄
// webpack.config.js
module.exports = {
// ...
plugins: [ // 數(shù)組:放著所有的webpack插件
new MiniCssExtractPlugin({
filename: 'css/main.css'
})
]
// ...
}