https://github.com/Yanlin-Zhu/webpack
webpack安裝
安裝本地webpack
安裝webpack和webpack-cli
//安裝前先npm初始化
npm init -y
npm i webpack webpack-cli -D
webpack可以進(jìn)行0配置(默認(rèn)只支持打包js文件)
- 打包工具 - 輸出后的結(jié)果(js模塊)
- 打包 - 支持js模塊化
運(yùn)行npx webpack會(huì)進(jìn)入node_modules/bin/webpack.cmd文件執(zhí)行
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\webpack\bin\webpack.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\webpack\bin\webpack.js" %*
)
判斷是否有node.exe沒有則執(zhí)行上一級webpack文件中的\bin\webpack.js文件
手動(dòng)配置webpack
- 默認(rèn)配置文件名字webpack.config.js
// webpack是node寫出來的 node的寫法
let path = require('path')
module.exports = {
mode: 'development', // 模式默認(rèn)有兩種production development開發(fā)模式代碼不壓縮看的清晰
entry: './src/index.js', // 入口文件
output: {
filename: '/js/bundle.[hash].js', // 打包后文件名
path: path.resolve(__dirname, 'dist'), //打包后路徑必須是絕對路徑resolve方法把相對路徑解析成絕對路徑数尿,__dirname加不加都可以,它代表在當(dāng)前目錄下產(chǎn)生一個(gè)dist目錄
publicPath: 'http://www.weilongyun.com' // 給所有打包文件引入時(shí)加前綴术健,包括css渺鹦,js序仙,img,如果只想處理圖片可以單獨(dú)在url-loader配置中加publicPath(上傳七牛云等cdn加速時(shí)可用)
},
}
三種hash值區(qū)別如下
https://www.cnblogs.com/giggle/p/9583940.html
打包后文件分析(可略過)
(function(modules) { // webpackBootstrap
// The module cache 先定義一個(gè)緩存
var installedModules = {};
// The require function 配置實(shí)現(xiàn)了require函數(shù)
function __webpack_require__(moduleId) { // 參數(shù)"./src/index.js"
// 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 執(zhí)行傳入this指向,模塊踢故,模塊的空對象exports: {}塑崖,require方法
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"); // 傳入入口模塊
})
// 自執(zhí)行函數(shù)傳入一個(gè)對象即modules
({
"./src/a.js": // key
(function(module, exports) { // value
eval("module.exports = 'a_moudle'\n\n//# sourceURL=webpack:///./src/a.js?");
}),
"./src/index.js":
(function(module, exports, __webpack_require__) {
eval("let str = __webpack_require__(/*! ./a.js */ \"./src/a.js\")\r\n\r\nconsole.log(str)\n\n//# sourceURL=webpack:///./src/index.js?");
})
});
在package.json中配置運(yùn)行腳本
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.js"
},
webpack-dev-server起本地服務(wù)
安裝
npm i webpack-dev-server -D
devServer: { // 開發(fā)服務(wù)器的配置(webpack-dev-server)
port: 3000,
progress: true,
contentBase: './dist' // 執(zhí)行時(shí)執(zhí)行打包后文件七冲,可以不配置
},
html-webpack-plugin(安裝插件打包html)
安裝
npm i html-webpack-plugin -D
let HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [ // 數(shù)組,放著所有webpack插件
new HtmlWebpackPlugin({ // 用于使用模板打包時(shí)生成index.html文件弃舒,并且在run dev時(shí)會(huì)將模板文件也打包到內(nèi)存中
template: './index.html', // 模板文件
filename: 'index.html', // 打包后生成文件
hash: true, // 添加hash值解決緩存問題
minify: { // 對打包的html模板進(jìn)行壓縮
removeAttributeQuotes: true, // 刪除屬性雙引號
collapseWhitespace: true // 折疊空行變成一行
}
})
]
css-loader style-loader(使用loader打包c(diǎn)ss文件)
安裝
npm i css-loader style-loader -D
配置
module: { // 模塊
// loader
rules: [ // 規(guī)則 loader的特點(diǎn)-希望單一功能
// css-loader-解析css文件包括css文件的引入(@import)語法等
// style-loader-把css文件插入到head標(biāo)簽中
{
test: /\.css/,
// 字符串只用一個(gè)loader癞埠,多個(gè)loader用數(shù)組配置
// loader的順序默認(rèn)從右向左執(zhí)行状原,從下到上執(zhí)行
// 如果需要傳參loader還可以配置成對象
use: ['style-loader', 'css-loader']
}
]
}
解析less文件配置
安裝
npm i less-loader -D
配置
// 可處理less文件除此之外還有sass、stylus
// node-sass苗踪、sass-loader颠区、stylus-loader
{
test: /\.less$/,
use: [
'style-loader', // 插入style標(biāo)簽
'css-loader', // 解析路徑
'less-loader' // 把less轉(zhuǎn)換成css
]
}
在只安裝了less-loader、css-loader通铲、style-loader時(shí)引入less文件報(bào)錯(cuò)Cannot find module 'less'毕莱,此時(shí)安裝less就好了
npm i less -D
mini-css-extract-plugin(抽離css插件)
安裝
npm i mini-css-extract-plugin -D
配置
let MiniCssExtractPlugin = require('mini-css-extract-plugin')
new MiniCssExtractPlugin({ // 抽離css樣式
filename: '/css/main.css'// 抽離出來的文件名
})
{
test: /\.css$/,
// 字符串只用一個(gè)loader,多個(gè)loader用數(shù)組配置
// loader的順序默認(rèn)從右向左執(zhí)行颅夺,從下到上執(zhí)行
// 如果需要傳參loader還可以配置成對象
use: [
// 'style-loader',
MiniCssExtractPlugin.loader, // 將css文件抽離出來朋截,不再以style標(biāo)簽存放,而是創(chuàng)建link標(biāo)簽引入
'css-loader'
]
},
// 可處理less文件除此之外還有sass吧黄、stylus
// node-sass部服、sass-loader、stylus-loader
{
test: /\.less$/,
use: [
// 'style-loader', // 插入style標(biāo)簽
MiniCssExtractPlugin.loader, // 將less文件抽離出來拗慨,不再以style標(biāo)簽存放廓八,而是創(chuàng)建link標(biāo)簽引入
'css-loader', // 解析路徑
'less-loader' // 把less轉(zhuǎn)換成css
]
}
使用mini-css-extract-plugin抽離css插件文件時(shí)可使用optimize-css-assets-webpack-plugin優(yōu)化壓縮css以及js文件
optimize-css-assets-webpack-plugin
使用optimize-css-assets-webpack-plugin壓縮css文件就必須使用uglifyjs-webpack-plugin壓縮js文件
雖然webpack 5可能帶有一個(gè)內(nèi)置的CSS最小化器,但對于webpack 4赵抢,您需要自帶一個(gè)CSS最小化器剧蹂。為了縮小輸出,可以使用像optimize-css-assets-webpack-plugin這樣的插件烦却。設(shè)置優(yōu)化宠叼。最小化器覆蓋webpack提供的默認(rèn)值,所以請確保還指定了JS最小化器:
安裝
npm i optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
配置
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
optimization: { // 優(yōu)化項(xiàng)
minimizer: [
new UglifyJsPlugin({ // 壓縮js
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({}) // 壓縮css
]
},
autoprefixer包(自動(dòng)給css樣式添前綴)該包需要通過postcss-loader處理
安裝
npm i postcss-loader autoprefixer -D
webpack.config.js中配置
{
test: /\.css$/,
// 字符串只用一個(gè)loader其爵,多個(gè)loader用數(shù)組配置
// loader的順序默認(rèn)從右向左執(zhí)行冒冬,從下到上執(zhí)行
// 如果需要傳參loader還可以配置成對象
use: [
// 'style-loader',
MiniCssExtractPlugin.loader, // 將css文件抽離出來,不再以style標(biāo)簽存放醋闭,而是創(chuàng)建link標(biāo)簽引入
'css-loader',
'postcss-loader'
]
},
// 可處理less文件除此之外還有sass窄驹、stylus
// node-sass、sass-loader证逻、stylus-loader
{
test: /\.less$/,
use: [
// 'style-loader', // 插入style標(biāo)簽
MiniCssExtractPlugin.loader, // 將less文件抽離出來乐埠,不再以style標(biāo)簽存放,而是創(chuàng)建link標(biāo)簽引入
'css-loader', // 解析路徑
'postcss-loader',
'less-loader' // 把less轉(zhuǎn)換成css
]
}
新建postcss.config.js配置文件
module.exports = {
plugins: [require('autoprefixer')]
}
js處理
使用babel將ES6或更高級的語法轉(zhuǎn)換成ES5
安裝
npm i babel-loader @babel/core @babel/preset-env -D
配置
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: { // 用babel-loader吧es6轉(zhuǎn)換成es5
presets: [ // 預(yù)設(shè)規(guī)則
'@babel/preset-env'
]
}
}
]
}
未使用babel前使用es6語法會(huì)報(bào)錯(cuò)
ERROR in bundle.d92a2720a0d7daf51415.js from UglifyJs
Unexpected token: name (str) [./src/index.js:1,0][bundle.d92a2720a0d7daf51415.js:91,4]
此時(shí)寫類和裝飾器(es7)還是會(huì)報(bào)錯(cuò)
ERROR in ./src/index.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: D:\zhuyanlin\webpack\src\index.js: Support for the experimental syntax 'classProperties' isn't currently enabled (8:5):
安裝
npm i @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D
配置
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: { // 用babel-loader吧es6轉(zhuǎn)換成es5
presets: [ // 預(yù)設(shè)規(guī)則
'@babel/preset-env'
]囚企,
plugins: [ // 此處配置有順序
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
}
]
}
如果您手動(dòng)包含插件并使用@babel/plugin-proposal-class屬性丈咐,請確保@babel/plugin-proposal-class裝飾器位于@babel/plugin-proposal-class屬性之前。
npm i @babel/plugin-transform-runtime -D
npm i @babel/runtime -S
plugins: [ // 此處配置有順序
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
"@babel/plugin-transform-runtime"
]
全局變量的引入(jQuery龙宏、Lodash...)
安裝
npm i jquery -S
配置
let webpack = require('webpack')
new webpack.ProvidePlugin({ // 在每個(gè)模塊中都注入$
$: 'jquery'
})
當(dāng)使用cdn在模板中引入時(shí)<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>可通過配置
externals: {
jquery: "$"
},
此時(shí)可以通過$或window.$調(diào)用棵逊,再在文件中寫import $ from 'jquery'時(shí)依然采用外部引入jQuery就不會(huì)被打包,打包文件不會(huì)增大银酗。
打包圖片
- 在js中創(chuàng)建圖片引入
import lion from './static/img/img/lion' // 把圖片引入返回一個(gè)新的圖片地址
let image = new Image()
image.src = lion
document.body.appendChild(image)
- 在css背景圖片中引入
background: url('./static/img/img/ABC.png')
- 在html中通過標(biāo)簽引入
file-loader(適用于前兩種情況引入圖片辆影,貌似可以不用也沒報(bào)錯(cuò))
file-loader默認(rèn)會(huì)生成一張圖片到dist目錄下徒像,把生成圖片的名字返回回來
安裝
npm i file-loader -D
配置
{
test: /\.(png|jpg|gif)$/,
use: 'file-loader'
}
html-withimg-loader(適用于html標(biāo)簽引入圖片)
安裝
npm i html-withimg-loader -D
配置
{
test: /\.html$/,
use: 'html-withimg-loader'
}
url-loader(可取代file-loader包含file-loader的功能)
安裝
npm i url-loader -D
配置
{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
// 做一個(gè)限制,當(dāng)圖片小于多少k時(shí)用base64轉(zhuǎn)化蛙讥,否則用file-loader將圖片產(chǎn)出
options: {
limit: 200*1024,
// dist打包文件中的輸出路徑
outputPath: '/img/'
}
}
}
打包多頁面應(yīng)用
代碼在git上的morepage分支npx webpack運(yùn)行打包
let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
// 多入口
entry: {
home: './src/index.js',
other: './src/other.js'
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'home.html',
chunks: ['home'] // 模板引入homejs模塊
}),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'other.html',
chunks: ['other'] // 模板引入otherjs模塊
})
]
}
配置source-map
// 源碼映射锯蛀,打包時(shí)會(huì)在dist中單獨(dú)生成一個(gè)source-map(.map)文件,出錯(cuò)時(shí)會(huì)標(biāo)識打包前文件當(dāng)前出錯(cuò)的類和行
// devtool: 'source-map', // 增加的映射文件可以幫我們調(diào)試源代碼次慢,特點(diǎn):大和全
// devtool: 'eval-source-map', // 不會(huì)產(chǎn)生單獨(dú)的映射文件會(huì)直接打包到打包文件中旁涤,可以產(chǎn)生報(bào)錯(cuò)行和列
// devtool: 'cheap-module-source-map', // 不會(huì)產(chǎn)生列,會(huì)產(chǎn)生一個(gè)單獨(dú)的映射文件
devtool: 'cheap-module-eval-source-map', // 不會(huì)產(chǎn)生文件迫像,也不會(huì)產(chǎn)生列
performance: {
hints:false
},
watch的用法劈愚,修改代碼后實(shí)時(shí)打包文件
watch: ture,
watchOptions: { // 監(jiān)控選項(xiàng)
poll: 1000, // 每秒問我一千次
aggregateTimeout: 500, // 防抖,我一直輸入代碼
ignored: /node_modules/ // 不需要監(jiān)控的文件
}
webpack的三個(gè)插件
1.cleanWebpackPlugin:刪除上次打包的文件
安裝
npm i clean-webpack-plugin -D
配置
let CleanWebpackPlugin = require("clean-webpack-plugin")
new CleanWebpackPlugin()
2.copyWebpackPlugin:將文檔等內(nèi)容打包進(jìn)打包文件
安裝
npm i copy-webpack-plugin -D
配置
let CopyWebpackPlugin = require("copy-webpack-plugin")
new CopyWebpackPlugin([
{from: './src/doc', to: './'}
])
3.bannerPlugin (內(nèi)置):打包后文件中版權(quán)作者等標(biāo)注信息
配置
let webpack = require('webpack')
new webpack.BannerPlugin('make 2019 by zhuyanlin')
webpack跨域
配置代理
proxy:{
"/fe": {
target: "http://127.0.0.1:3000",
changeOrigin: true,
ws: true,
pathRewrite: {
"^/fe": ""
}
}
}
resolve
解析順序別名等配置
https://www.webpackjs.com/configuration/resolve/#resolve
定義環(huán)境變量
new webpack.DefinePlugin({
DEV: JSON,stringify('dev'),
AAA: 'true'
})
區(qū)分不同環(huán)境
將不環(huán)境配置文件分開
npm i webpack-merge -D
noParse
不去解析某些包中的依賴關(guān)系
IgnorePlugin moment庫(時(shí)間插件)
npm i moment -S
import moment from 'moment';
console.log(moment().endOf('day').fromNow())
dullPlugin
npm i react react-dom -S
npm i @babel/preset-react -D
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: { // 用babel-loader吧es6轉(zhuǎn)換成es5
presets: [ // 預(yù)設(shè)規(guī)則
'@babel/preset-env',
'@babel/preset-react'
],
plugins: [ // 此處配置有順序
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
// "@babel/plugin-transform-runtime"
]
}
}
],
// exculde: /node_modules/
// inculde: path.resolve(__dirname, 'src')
},
闻妓。菌羽。。未完待續(xù)
webpack生命周期
http://taobaofed.org/blog/2016/09/09/webpack-flow/
webpack搭建一個(gè)react項(xiàng)目并優(yōu)化
npm init // 創(chuàng)建package.json
npm i webpack -D
npm i react react-dom -S
npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev
npm i html-webpack-plugin html-loader --save-dev
npm i webpack-dev-server --save-dev
// webpack.config.json
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = {
entry: path.resolve(__dirname, './src/index.js'), //指定入口文件由缆,程序從這里開始編譯,__dirname當(dāng)前所在目錄, ../表示上一級目錄, ./同級目錄
output: {
path: path.resolve(__dirname, './dist'), // 輸出的路徑
filename: 'bundle.js' // 打包后文件
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
}
},
exclude: /node_modules/
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./index.html",
filename: "./index.html"
})
],
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 9000
}
}
HappyPack
分進(jìn)程變異
npm i -D happypack
懶加載和預(yù)加載算凿,webpack生產(chǎn)環(huán)境自帶優(yōu)化,搖樹優(yōu)化和變量提升
抽離公共代碼用于打包多入口項(xiàng)目