webpack 的 基础知识

  |  

1、介绍

Webpack是⼀个打包模块化JavaScript的⼯具,它会从⼊⼝模块出发,
识别出源码中的模块化导⼊语句,递归地找出⼊⼝⽂件的所有依赖,将⼊
⼝和其所有的依赖打包到⼀个单独的⽂件中
是⼯程化、⾃动化思想在前端开发中的体现

2、安装

全局安装(不推荐)

# 安装webpack V4+版本时,需要额外安装webpack-cli
npm install webpack webpack-cli -g
# 检查版本
webpack -v
# 卸载
npm uninstall webpack webpack-cli -g

全局安装webpack,这会将你项⽬中的webpack锁定到指定版本,造成不
同的项⽬中因为webpack依赖不同版本⽽导致冲突,构建失败

项目安装(推荐)

# 安装最新的稳定版本
npm i -D webpack
# 安装指定版本
npm i -D webpack@<version>
# 安装最新的体验版本 可能包含bug,不要⽤于⽣产环境
npm i -D webpack@beta
# 安装webpack V4+版本时,需要额外安装webpack-cli
npm i -D webpack-cli

3、webpack配置核心概念

零配置是很弱的,特定的需求,总是需要⾃⼰进⾏配置
webpack有默认的配置⽂件,叫webpack.config.js,我们可以
对这个⽂件进⾏修改,进⾏个性化配置

  • 使⽤默认的配置⽂件:webpack.config.js
  • 不使⽤⾃定义配置⽂件: ⽐如webpackconfig.js,可以通过–
    config webpackconfig.js来指定webpack使⽤哪个配置⽂件来
    执⾏构建

webpack.config.js配置基础结构

module.exports = {
entry: "./src/index.js", //打包⼊⼝⽂件
output: "./dist", //输出结构
mode: "production", //打包环境
module: {
rules: [
//loader模块处理
{
test: /\.css$/,
use: "style-loader"
}
]
},
plugins: [] //插件配置
};

3.1-entry

指定webpack打包⼊⼝⽂件:Webpack 执⾏构建的第⼀步将从
Entry 开始,可抽象成输⼊

//单⼊⼝ SPA,本质是个字符串
entry:{
main: './src/index.js'
}
// ==相当于简写===
entry:"./src/index.js"


//多⼊⼝ entry是个对象
entry:{
index:"./src/index.js",
login:"./src/login.js"
}

3.2 output

打包转换后的⽂件输出到磁盘位置:输出结果,在 Webpack 经过⼀
系列处理并得出最终想要的代码后输出结果。

output: {
filename: "bundle.js",//输出⽂件的名称
path: path.resolve(__dirname, "dist")//输出⽂件到
// 磁盘的⽬录,必须是绝对路径
},

//多⼊⼝的处理
output: {
filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重复
path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
},

3.3-mode

Mode⽤来指定当前的构建环境

设置mode可以⾃动触发webpack内置的函数,达到优化的效果

  • development: 会将DefinePlugin中的 process.env.NODE_DEV的值设置为
    development。启用NameChunksPlugin和NameModulesPlugin。

  • production: 会将DefinePlugin中的 process.env.NODE_DEV的值设置为
    production。启用FlagDepenndencyUsagePlugin, FlagIncludedChunksPlugin,
    ModuleConcatenationPlugin等

  • none 退出任何默认优化选项

3.4-loader

Webpack 默认只⽀持.json 和 .js模块 不⽀持 不认识其他格式的模

模块解析,模块转换器,⽤于把模块原内容按照需求转换成新内
容。

webpack是模块打包⼯具,⽽模块不仅仅是js,还可以是css,图⽚
或者其他格式,但是webpack默认只知道如何处理js和JSON模块,那么其他格式的
模块处理,和处理⽅式就需要loader了

常见loader
style-loader
css-loader
less-loader
sass-loader
ts-loader //将Ts转换成js
babel-loader//转换ES6、7等js新特性语法
file-loader//处理图⽚⼦图
eslint-loader
...

3.5-module

模块,在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。
Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。

当webpack处理到不认识的模块时,需要在webpack中的module
处进⾏配置,当检测到是什么格式的模块,使⽤什么loader来处
理。

module:{
rules:[
{
test:/\.xxx$/,//指定匹配规则
use:{
loader: 'xxx-load'//指定使⽤的loader
}
}
]
}

下面的配置,包括了对图片,样式文件,字体等的处理

module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
// "style-loader",
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
//css modules 开启
modules: true,
},
},
{
// 自动添加前缀
loader: "postcss-loader",
},
"less-loader",
],
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
name: "[name]_[hash:6].[ext]",
outputPath: "images/",
//推荐使用url-loader 因为url-loader支持limit
//推荐小体积的图片资源转成base64
limit: 12 * 1024, //单位是字节 1024=1kb
},
},
},
{
test: /\.(eot|ttf|woff|woff2|svg)$/,
use: "file-loader"
}
],
},

多个loader执行是有顺序的

loader执行从右到左,从下到上

3.6 Plugins

  • 作⽤于webpack打包整个过程
  • webpack的打包过程是有(⽣命周期概念)钩⼦

plugin 可以在webpack运⾏到某个阶段的时候,帮你做⼀些事情,
类似于⽣命周期的概念

扩展插件,在 Webpack 构建流程中的特定时机注⼊扩展逻辑来改
变构建结果或做你想要的事情

常用的有下面的插件

HtmlWebpackPlugin (自动生成html文件,并将打包的js模块引入到该html)

clean-webpack-plugin (自动删除上一次打包文件)

mini-css-extract-plugin (将css抽离成单独的文件)
...
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "css/[name]-[contenthash:8].css",
}),
new HtmlWebpackPlugin({
//选择html模板
title: "首页",
template: "./src/index.html",
filename: "index.html",
}),
],

sourceMap

源代码与打包后的代码的映射关系,通过sourceMap定位到源代
码。
在dev模式中,默认开启,关闭的话 可以在配置⽂件⾥

devtool:"none"

eval:速度最快,使⽤eval包裹模块代码,
source-map: 产⽣.map⽂件
cheap:较快,不包含列信息
Module:第三⽅模块,包含loader的sourcemap(⽐如jsx to js ,
babel的sourcemap)
inline: 将.map作为DataURI嵌⼊,不单独⽣成.map⽂件

配置推荐:

devtool:"cheap-module-eval-source-map",// 开发环境配置
//线上不推荐开启, 但是要的建议使用 下面
devtool:"cheap-module-source-map", // 线上⽣成配置

WebpackDevServer(提升开发效率的利器)

每次改完代码都需要重新打包⼀次,打开浏览器,刷新⼀次,很麻
烦,我们可以安装使⽤webpackdevserver来改善这块的体验

安装

npm install webpack-dev-server -D

配置

修改下package.json

"scripts": {
"server": "webpack-dev-server"
},

在webpack.config.js配置

devServer: {
contentBase: "./dist",
open: true,
port: 8081
},

启动

npm run server

启动服务后,会发现dist⽬录没有了,这是因为devServer把打包后
的模块不会放在dist⽬录下,⽽是放到内存中,从⽽提升速度

本地mock,解决跨域:

联调期间,前后端分离,直接获取数据会跨域,上线后我们使⽤
nginx转发,开发期间,webpack就可以搞定这件事

启动⼀个服务器,mock⼀个接⼝:

// server.js
const express = require('express')
const app = express()
app.get('/api/info', (req,res)=>{
res.json({
name:'foo',
age:5,
msg:'welcome'
})
})
app.listen('9099')

修改webpack.config.js 设置服务器代理

proxy: {
"/api": {
target: "http://localhost:9099"
}
}

Hot Module Replacement (HMR:热模块替换)

不⽀持抽离出的css 我们要使⽤css-loader

启动HMR

devServer: {
contentBase: "./dist",
open: true,
hot:true,
//即便HMR不⽣效,浏览器也不⾃动刷新,就开启hotOnly
hotOnly:true
},

配置⽂件头部引⼊webpack, 同时在插件配置处添加插件代码

const path = require("path");
const HtmlWebpackPlugin = require("html-webpackplugin");
const CleanWebpackPlugin = require("clean-webpackplugin");
const webpack = require("webpack");
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "src/index.html"
}),
new webpack.HotModuleReplacementPlugin()
],

注意启动HMR后,css抽离会不⽣效,还有不⽀持contenthash,chunkhash

处理js模块HMR

需要使⽤module.hot.accept来观察模块更新 从⽽更新

//counter.js
function counter() {
var div = document.createElement("div");
div.setAttribute("id", "counter");
div.innerHTML = 1;
div.onclick = function () {
div.innerHTML = parseInt(div.innerHTML, 10) + 1;
};
document.body.appendChild(div);
}
export default counter;
//number.js
function number() {
var div = document.createElement("div");
div.setAttribute("id", "number");
div.innerHTML = 13000;
document.body.appendChild(div);
}
export default number;

//index.js
import counter from "./counter";
import number from "./number";
counter();
number();
if (module.hot) {
module.hot.accept("./b", function () {
document.body.removeChild(document.getElementById("number"));
number();
});
}

Bable处理ES6

Babel是JavaScript编译器,能将ES6代码转换成ES5代码,让我们
开发过程中放⼼使⽤JS新特性⽽不⽤担⼼兼容性问题。并且还可以
通过插件机制根据需求灵活的扩展。

Babel在执⾏编译的过程中,会从项⽬根⽬录下的.babelrc JSON
⽂件中读取配置。没有该⽂件会从loader的options地⽅读取配
置。

安装

npm i babel-loader @babel/core @babel/preset-env -D

1.babel-loader是webpack 与 babel的通信桥梁,不会做把es6转成
es5的⼯作,这部分⼯作需要⽤到@babel/preset-env来做

2.@babel/preset-env⾥包含了es,6,7,8转es5的转换规则

配置

Webpack.config.js

{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
};

通过上⾯的⼏步 还不够,默认的Babel只⽀持let等⼀些基础的特性
转换,Promise等⼀些还有转换过来,这时候需要借助
@babel/polyfill,把es的新特性都装进来,来弥补低版本浏览器中
缺失的特性

@babel/polyfill

npm install --save @babel/polyfill

// 然后使用
//index.js 顶部
import "@babel/polyfill";

按需加载,减少冗余

会发现打包的体积⼤了很多,这是因为polyfill默认会把所有特性注
⼊进来,假如我想我⽤到的es6+,才会注⼊,没⽤到的不注⼊,从
⽽减少打包的体积,可不可以呢

options: {
presets: [
[
"@babel/preset-env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
corejs: 2, //新版本需要指定核⼼库版本
useBuiltIns: "usage", //按需注⼊
},
],
];
}

useBuiltIns选项是babel 7的新功能,这个选项告诉babel如何
配置@babel/polyfill。 它有三个参数可以使⽤:

①entry: 需要
在webpack的⼊⼝⽂件⾥import “@babel/polyfill”⼀
次。babel会根据你的使⽤情况导⼊垫⽚,没有使⽤的功能不会被
导⼊相应的垫⽚。

②usage: 不需要import,全⾃动检测,但是要
安装@babel/polyfill。(试验阶段)

③false: 如果你import
“@babel/polyfill”,它不会排除掉没有使⽤的垫⽚,程序体积会
庞⼤。(不推荐)

我可以单独配置bable,而不是作为option选项

新建 .babelrc文件

// .babelrc
{
presets: [
[
"@babel/preset-env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
corejs: 2, //新版本需要指定核⼼库版本
useBuiltIns: "usage", //按需注⼊
},
],
];
}
// 然后修改 webpack.config.js文件的loader

{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}

基本配置文件

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const webpack = require("webpack");

//
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
entry: "./src/index.js",
mode: "development",
output: {
path: path.resolve(__dirname, "./dist"),
filename: "[name].js",
publicPath: "https://cdn.kaikeba.com/assets/",
},
module: {
//loader是一个消耗性能的大户
//2065ms
//1710ms
rules: [
{
test: /\.css$/,
include: path.resolve(__dirname, "./src"),
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
include: path.resolve(__dirname, "./src"),
use: [
// "style-loader",
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
//css modules 开启
modules: true,
},
},
{
loader: "postcss-loader",
},
"less-loader",
],
},
{
test: /\.(png|jpe?g|gif)$/,
include: path.resolve(__dirname, "./src"),
use: {
loader: "url-loader",
options: {
name: "[name]_[hash:6].[ext]",
outputPath: "images/",
//推荐使用url-loader 因为url-loader支持limit
//推荐小体积的图片资源转成base64
limit: 12 * 1024, //单位是字节 1024=1kb
},
},
},
{
test: /\.js$/,
include: path.resolve(__dirname, "./src"),
use: {
loader: "babel-loader",
},
},
],
},
resolve: {
//查找第三方依赖
modules: [path.resolve(__dirname, "./node_modules")],
alias: {
//减少查找过程
//起别名
"@": path.resolve(__dirname, "./src"),
// react: "./node_modules/react/umd/react.production.min.js",
// "react-dom": "./node_modules/react-dom/umd/react-dom.production.min.js",
},
extensions: [".js", ".json"],
},
externals: {
//jquery通过script引入之后,全局中即有了 jQuery 变量
lodash: "_",
},
devtool: "cheap-inline-source-map",
// devServer: {
// //可以是相对路径
// contentBase: "./dist",
// open: true,
// hot: true,
// //即便HMR没有生效,浏览器也不要自动刷新。
// hotOnly: true,
// //代理
// proxy: {
// "/api": {
// target: "http://localhost:9092",
// },
// },
// //mock server
// before(app, server) {
// app.get("/api/mock.json", (req, res) => {
// res.json({
// hello: "express",
// });
// });
// },
// port: 8080,
// },
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "css/[name]-[contenthash:8].css",
}),
new OptimizeCSSAssetsPlugin({
cssProcessor: require("cssnano"), //引入cssnano引擎
cssProcessorOptions: {
discardComments: { removeAll: true },
},
}),
new HtmlWebpackPlugin({
//选择html模板
title: "首页",
template: "./src/index.html",
filename: "index.html",
minify: {
// 压缩HTML文件
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true, // 压缩内联css
},
}),
// new webpack.HotModuleReplacementPlugin(),
],
};

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 1、介绍
  2. 2. 2、安装
    1. 2.1. 全局安装(不推荐)
    2. 2.2. 项目安装(推荐)
  3. 3. 3、webpack配置核心概念
    1. 3.1. 3.1-entry
    2. 3.2. 3.2 output
    3. 3.3. 3.3-mode
    4. 3.4. 3.4-loader
      1. 3.4.1. 常见loader
    5. 3.5. 3.5-module
    6. 3.6. 3.6 Plugins
  4. 4. sourceMap
  5. 5. WebpackDevServer(提升开发效率的利器)
    1. 5.1. 安装
    2. 5.2. 配置
    3. 5.3. 启动
    4. 5.4. 本地mock,解决跨域:
  6. 6. Hot Module Replacement (HMR:热模块替换)
    1. 6.1. 启动HMR
    2. 6.2. 处理js模块HMR
  7. 7. Bable处理ES6
    1. 7.1. 安装
    2. 7.2. 配置
    3. 7.3. @babel/polyfill
    4. 7.4. 按需加载,减少冗余
  8. 8. 基本配置文件
,