本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具 。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图 ,然后将你项目中所需的每一个模块组合成一个或多个 bundles ,它们均为静态资源,用于展示你的内容
注意:全局安装可以直接使用 webpack 命令打包,但不推荐,避免将项目中的 webpack 锁定到指定版本,并且在使用不同的 webpack 版本的项目中, 可能会导致构建失败。
1、安装 webpack 和 webpack-cli, webpack-cli 是在 node 下运行所必须的
mkdir webpack-demo
cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev
2、修改 package.json,增加"build": "webpack"
这里可以自行设置入口和出口,如 webpack --entry ./src/main.js --output-path ./build
{
"name": "learn-webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1"
}
}
3、运行 webpack 进行打包
npm run build
默认情况下无法处理 css 、 less 文件,需要对文件进行转换,loader 就是起到一个转换的作用
css 并非 js 模块, 需要使用 css-loader 识别模块并解析出依赖关系, style-loader 才可以解析并生成样式
npm i css-loader -D
npm i style-loader -D
npm i less-loader -D
import "css-loader!../css/example.css";
webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.css$/, // 一般是匹配我们所需要处理的文件类型正则表达式
use: [
// 注意顺序,需先添加 style-loader 才能解析样式
// 按从上往下或从右往左顺序执行
// 未配置 options 可简写未 use: ['style-loader', 'css-loader']
{
loader: "style-loader",
},
{
loader: "css-loader",
},
],
},
// 下面采用简写方式
{
test: /\.less$/,
// 这里还是需要添加 css-loader
use: ["style-loader", "css-loader", "less-loader"],
},
],
},
};
目前前端开发均采用工程化方式,不仅需要考虑对各类工具包的兼容性,需要考虑浏览器对 CSS 语法、 JS 语法的兼容性,browserslistrc 可以帮助我们完成目标环境配置。 browserslist 单独是没用的,需要结合 bable 、 autoprefixer 等工具来确定需转译的 JS 特性和需要添加的 CSS 浏览器前缀。它的查询数据来源于 Can I Use
package.json 增加如下代码,表示兼容市场占有率大于 1% 或最新两个版本或最近24个月有更新维护的浏览器
{
"browserslist": [
">1%",
"last 2 versions",
"not dead",
"not ie <= 8"
]
}
或
添加 .browerslistrc 配置文件书写如下代码
> 1%
last 2 versions
not dead
not ie <= 8
一个通过 JS 来转换样式的工具,以达到兼容性
要在命令行中使用 postcss 还需安装 postcss-cli ,并安装 autoprefixer 添加前缀,最后生成待前缀的 css
npm i postcss -D
npm i postcss-cli -D
npx i autoprefixer -D
npx postcss --use autoprefixer -o ret.css ./src/css/test.css
应该放在 css-loader 之前加载,以加上前缀
{
loader: "postcss-loader",
options: {
postcssOptions: {
// plugins: [require("autoprefixer")],
// postcss-preset-env 是一个预设——插件集合
// 包含了autoprefixer,支持简写,当然 autoprefixer 也支持简写
plugins: ["postcss-preset-env"],
},
}
}
// 顺序 [style-loader, css-loader, postcss-loader]
在一个 css 文件中导入另一个 css 文件来使用其中的样式时,由于 css 被匹配到后 postcss-loader 先进行工作添加前缀,然后再把代码传递给 css-loader , css-loader 可以处理 @import 导入的内容或者 @import meida 、 url 之类的内容,但并不会再回头交给 postcss-loader 处理,而是直接交给 style-loader 进行展示,这样我们就需要用到 importLoaders 属性指定配置的 css-loader 作用于 @import 的资源之前有多少个 loader
{
loader: "css-loader",
options: {
importLoaders: 1,
},
}
npm i file-load -d
使用 file-loader 会在 /dist 目录中生成导出的图片,他会把文件名称、路径返回并拷贝到打包目录,还要分开请求图片,请求次数变多
// 添加图片
function pckImg() {
const oEle = document.createElement("div");
const oImg = document.createElement("img");
oImg.src = require("../img/webpack.png").default; // webpack5 得加 default
oEle.appendChild(oImg);
return oEle;
}
document.body.appendChild(pckImg());
// 配置 webpack rules
{
test: /\.(png|svg|gif|jpg|jpeg)$/,
use: ["file-loader"],
},
// 不使用 .default 的方法一
use: [
{
loader: "file-loader",
options: {
esModule: false, // 是否将导出的内容转为 esModule
},
},
],
// 不使用 .default 的方法二
import oImgSrc from "../img/webpack.png"
function pckImg() {
const oEle = document.createElement("div");
const oImg = document.createElement("img");
oImg.src = oImgSrc;
oEle.appendChild(oImg);
return oEle;
}
document.body.appendChild(pckImg());
// 添加盒子及 css
import "../css/img.css";
function pckImg() {
const oEle = document.createElement("div");
oEle.className = "bgBox";
return oEle;
}
document.body.appendChild(pckImg());
// 添加 file-loader
{
test: /\.(png|svg|gif|jpg|jpeg)$/,
use: [
{
loader: "file-loader",
options: {
esModule: false, // 是否将导出的内容转为 esModule
},
}
],
},
// 修改 css-loader, 如果不修改 esModule 属性为 false 同样会无法识别
// 需要添加 default, 但 css 不会允许那么去写
{
loader: "css-loader",
options: {
esModule: false, // 是否将导出的内容转为 esModule
},
},
文件名称占位符
[ext]:扩展名
[name]:文件名
[hash]:结合文件内容产生 hash
[contentHash]:在 file-loader 中于 作用一样
[hash: length]
[path]:路径,相对 webpack 配置文件
{
loader: "file-loader",
options: {
esModule: false,
// 文件名称
name: "[name].[hash:6].[ext]",
// 输出路径
outputPath: 'img'
// 简写 name: "img/[name].[hash:6].[ext]",
},
}
npm i url-loader -D
使用 url-loader 不会在 /dist 目录中生成导出的图片,而是以 base64URL 的方式加载到我们的资源中,减少请求次数。 url-loader 内部也可以调用 file-loader ,通过 limit 控制使用哪种方法
// 和 fileloader 用法一样, 还是要给 css loader 设置 esModule 属性为 false
{
test: /\.(png|svg|gif|jpg|jpeg)$/,
use: [
{
loader: "url-loader",
options: {
esModule: false,
name: "img/[name].[hash:6].[ext]",
limit: 25 * 1024, // 25KB, 超过25KB会交给 file-loader 处理,拷贝出来
},
},
],
}
base64URL:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cb2vy3Ri-1642001847935)(C:\Users\HeHao\AppData\Roaming\Typora\typora-user-images\image-20220104222133104.png)]
webpack5 后可以直接使用资源类型模块 asset module type 来简化 loader 的使用或替换,无需额外安装, webpack5 已内置
asset/resource ===> file-loader
asset/inline ===> url-loader
asset/source ===> raw-loader
asset
{
test: /\.(png|svg|gif|jpe?g)$/,
type: "asset/resource",
}
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "img/[name].[hash:6][ext]", // 这里有点区别,文件后最无需加.
},
module: {
rules: [
{
test: /\.(png|svg|gif|jpe?g)$/,
type: "asset/resource",
},
],
},
};
**缺点:**会把字体等资源也输出到 img 文件夹中
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.(png|svg|gif|jpe?g)$/,
type: "asset/resource",
generator: {
filename: "img/[name].[hash:6][ext]"
}
},
],
},
};
使用 asset , 添加 parser
{
test: /\.(png|svg|gif|jpe?g)$/,
type: "asset",
generator: {
filename: "img/[name].[hash:6][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 20 *1024,
}
}
}
{
test: /\.(ttf|eot|svg|woff2?)$/,
type: "asset/resource", // 也可以使用 inline 以Base64URL方式打包到 js ,但不能加 generator
generator: {
filename: "font/[name].[hash:3][ext]",
},
},
loader 和 plugin 的区别
loader:在读取特定内容时,对特定文件类型进行转换
plugin:使用灵活,贯穿 webpack 的整个生命周期,比 loader 可以做的事情更多
插件的本质上是一个类,有自己的构造函数和 apply 方法
第三方插件,每次打包清空 /dist 目录
npm i clean-webpack-plugin -D
webpack.config.js
// 引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
// 使用插件
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
module: {
...
},
plugins: [new CleanWebpackPlugin()], // 调用插件
};
自定义 index.html 配置到 ./public 目录
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="gb2312" />
<!-- 常量占位 DefinePlugin -->
<link rel="icon" href="<%= BASE_URL %>" />
<title>
<!-- 对象属性占位 html-webpack-plugin -->
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<script src="./dist/main.js"></script>
</body>
</html>
webpack.config.js
// 引入插件
const {DefinePlugin} = require("webpack"); // webpackb内置插件
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 添加插件配置
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "webpack 快速上手",
template: "./public/index.html", // 存放自己的静态资源
}),
new DefinePlugin({
// 常量写这里
BASE_URL:
// 这里必须用双层引号,否则打包的文件路径不会是字符串,引发 Unexpected token 错误
'"https://webpack.docschina.org/favicon.f326220248556af65f41.ico"',
}),
],
可以使用它拷贝文件到 ./dist 目录
npm i copy-webpack-plugin -D
const CopyWebpackPlugin = require("copy-webpack-plugin");
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "webpack 快速上手",
template: "./public/index.html",
}),
new DefinePlugin({
BASE_URL:
'"https://webpack.docschina.org/favicon.f326220248556af65f41.ico"',
}),
new CopyWebpackPlugin({
// 需拷贝的配置项
patterns: [
{
from: "public", // 从哪里 copy
// to: '', 这里可以省略 to,自动从 output 的 path 去找
globOptions: {
ignore: ['**/index.html']
// 这里必须在前面加 **/ 表示从当前路径下忽略
// 且忽略目录中文件后不能为空
}
},
],
}),
],
将 JSX TS ES6+ 转换成浏览器平台可以直接使用的代码
npm i @babel/core -D
npm i @babel/cli -D
npm i @babel/plugin-transform-arrow-functions -D
npm i @babel/plugin-transform-block-scoping -D
babel core 需要结合具体的转换插件才能转换为其他兼容性代码。将 ./src 中的所有 js 代码进行箭头函数和作用域转换,转换的文件放到 ./bulid 目录中
npx babel src --out-dir build --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping
安装预设,避免麻烦的单独安装和调用
npm i @babel/preset-env -D
使用预设,将 ./src 中的所有 js 代码使用预设进行转换,转换的文件放到 ./bulid 目录中
npx babel src --out-dir build --presets=@babel/preset-env
npm i babel-loader -D
{
test: /\.js$/,
use: [
{
loader: "babel-loader",
options: {
// 使用插件
// plugins: [
// "@babel/plugin-transform-arrow-functions",
// "@babel/plugin-transform-block-scoping",
// ],
// 使用预设
presets: ["@babel/preset-env"],
},
},
],
}
1、根据 browserslistrc 的配置(推荐,但主要是用于 postcss)
2、配置targets,与 browserslistrc 同时存在优先使用该配置
{
test: /\.js$/,
use: [
{
loader: "babel-loader",
options: {
// plugins: [
// "@babel/plugin-transform-arrow-functions",
// "@babel/plugin-transform-block-scoping",
// ],
presets: [
[
"@babel/preset-env",
{
targets: "chrome 91",
},
],
],
},
},
],
}
简化 babel-loader 配置,避免深层嵌套
现在推荐使用:babel.config.js 或json cjs mjs
babel7之前推荐使用:babelrc.json 或js mjs cjs 或直接 .babelrc
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: "chrome 91",
},
],
],
};
在遇到 Promise 、 generator 、 symbol 等一些更新语法时 @babel/preset-env 还是无法帮助我们进行转换,所有这个时候需要用到 polyfill 。 注意,在webpack4 默认加入 polyfill 导致产出文件特别大, webpack5 基于优化打包速度考虑已默认移除。
这里应该安装为生产依赖,因为生产环境下同样需要依赖它进行转化(babel 7.4.0 开始已被弃用)
npm i @babel/polyfill --save
但是整体来说 @babel/polyfill 包还是过大,如果只需要转换 已正式发布的 ECMAScript 标准进行转换,只需要安装 core-js/stable 和 regenerator-runtime/runtime (转换生成器函数) 两个包即可。
npm i core-js regenerator-runtime
在 js 入口文件引入两个包
import "core-js/stable";
import "regenerator-runtime/runtime";
作为 babel 的工具使用,配置babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
// 三个值,不写默认 false ,不对当前 JS 处理做 polyfill 的填充
// usage:依据用户源代码中使用到的新语法进行填充
// entry:依据需要兼容的浏览器进行填充
useBuiltIns: "usage",
corejs: 3,
},
],
],
};
webpack.config.js 的 js 规则中加入 exclude: /node_modules/
,因为部分使用的 node_modules 本身已经做了 polyfill ,应该排除
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
// plugins: [
// "@babel/plugin-transform-arrow-functions",
// "@babel/plugin-transform-block-scoping",
// ],
presets: ["@babel/preset-env"],
},
},
],
},
我们目前要打开编写好的网页每次都需要运行 npm run build
,否则无法通过修改代码同步修改 ./dist 中打包的代码,这样流程太过繁琐冗余,需要一种合理的解决方案来实现自动重新编译。
"build": "webpack --watch"
watch: true
缺点:
npm i webpack-dev-server -D
修改 package.json 增加短命令 "serve": "webpack serve"
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"serve": "webpack serve --config webpack.config.js"
}
开启 serve 静态服务,默认端口为 8080
npm run serve
优点:
webpack-dev-middleware
是一个封装器( wrapper ),它可以把 webpack 处理过的文件发送到一个 server。webpack-dev-server
在内部使用了它,然而它也可以作为一个单独的 package 来使用,以便根据需求进行更多自定义设置。(webpack-dev-server 使用较多)
安装 core-js、regenerator-runtime 、 express 、 webpack-dev-middleware
npm i core-js regenerator-runtime express webpack-dev-middleware
Server.js 模拟服务端,使用 webpack-middleware
// 模拟服务端
const express = require("express");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpack = require("webpack");
// 使用 express 开启服务
const app = express();
// 获取配置文件
const config = require("./webpack.config.js");
// compiler 控制打包流程
const compiler = webpack(config);
// 将结果交给 server
app.use(webpackDevMiddleware(compiler));
// 开启端口上的服务监听
app.listen(3000, () => {
console.log("服务运行在端口 3000 上");
});
// 开启服务
node ./Server.js
模块热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新。
配置:webpack.config.js
devServer: {
hot: true,
},
为模块开启热更新, index.js ,整个方法也提供了回调函数,在发生更新是运行
import "./title.js";
if (module.hot) {
module.hot.accept(["./title.js"], () => {
console.log("title.js 模块更新了");
});
}
React 配置HMR 还需要额外的配置
安装 @babel/core 、 @babel/preset-react
npm i @babel/preset-react -D
npm i @babel/core -D
在 webpack.config.json 添加 jsx 解析规则
// jsx
{
test: /\.jsx?$/, // 以该规则解析 js 和 jsx
use:['babel-loader']
}
在 babel.config.js 配置 babel
module.exports = {
presets: [
["@babel/preset-env"],
["@babel/preset-react"],
],
};
安装 react-refresh-webpack-plugin 和 react-refresh (前者依赖它,配合使用)
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
配置 package.json
plugins: [
new reactRefreshWebpackPlugin()
]
配置 babel.config
module.exports = {
presets: [
["@babel/preset-env"],
["@babel/preset-react"],
],
plugins: [["react-refresh/babel"]],
};
webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
// path :本地、产出---打包内容输出到本地的路径,使用 server 更多关注的是下面的 publicPath
path: path.resolve(__dirname, "dist"),
// publicPath : 告知静态资源 index.html 内部的引用路径
// 官网解释指定在浏览器中所引用的此输出目录对应的公开URL
// webpack-dev-server 也会默认从 publicPath 为基准
// 使用它来决定在哪个目录下启用服务,来访问 webpack 输出的文件
// 值为 域名 + publicPath + filename
// 默认为空串,浏览器会在还没补 '/',如果不想其补'/',可以写为'/'
// 但这样如果还想打包 build 到本地 ./dist ,会找不到
// 如果开启本地服务对其进行访问,建议使用 '/'
// 强烈建议和 devServer 中的 publicPath 设置为一样的
publicPath: '/',
}
};
webpack.config.js 注意,webpack5 已移除以下属性,可参考 static
const path = require("path");
module.exports = {
devServer: {
// 指定本地服务所在的目录,即在哪开启服务,服务资源存在哪个目录(URL) static.publicPath
publicPath: '/',
// 打包之后的资源可能存在引入了一个没有被打包的资源,可以使用改属性指定,推荐使用绝对路径 static.directory
contentBase: path.resolve(__dirname, 'public')
// 实现未打包资源修改时实时刷新操作 static.watch
watchContentBase: true
},
}
const path = require("path");
module.exports = {
devServer: {
// webpack5 已改为 hot: 'only'
// 遇到语法错误时值刷新错误的地方, 如果只是 hot 会全部刷新
hotOnly: true,
// 运行服务的端口
port: 4000,
// 每次更新后自动重新打开浏览器,不建议打开
open: false,
// 开启服务端,现已默认开启
compress: true,
// 当使用HTML5的 History API 时,index.html 页面可能会被用来代替任何 404 响应
// 启用 devServer 的 historyApiFallback设置为 true 即可实现
historyApiFallback
},
}
进行开发时,前后端可能不在一个端口上,或者需要请求其他地方的数据,那么就会存在浏览器跨域问题,就需要使用 proxy 进行代理
module.exports = {
//...
devServer: {
proxy: {
// /api 为标识符可以自定义,如果代码中出现 /api 字样就表明我们需要去转发请求
// 不问自己要而是问别人要数据
'/api': {
// 这里的 target 就是问谁要
// 现在对 /api/users (只需要书写http://localhost:4000/api/users)的请求
// 将请求代理到 https://api.github.com/users
target: 'http://https://api.github.com',
// 后端不一定按我们定义的标识符去书写接口, pathRewrite 表示我们要把接口重写成什么
// 这里假设后端接口就在 https://api.github.com
// 则请求 users 只需请求 https://api.github.com/users
pathRewrite: {"^/api" : ""},
// 默认情况下,代理时会保留主机头的来源,可以将 changeOrigin 设置为 true 以覆盖此行为
// 此处如果使用,那么请求的 HOST 可以看到(服务器才可以)被改成 https://api.github.com
changeOrigin: true,
},
},
},
};
配置模块如何被解析
resolve: {
// 模块中怎么去找,按顺序
modules: ['node_modules', "lg"],
// 解析目录时要使用的文件名,只写到文件夹怎么解析
mainFiles: ['index'],
// 没有后缀怎么解析
// 尝试按顺序解析这些后缀名
// 如果有多个文件有相同的名字,但后缀名不同
// webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀
extensions: [".js", ".json", ".ts", ".jsx", ".vue"]
// 使用别名
alias: {
"@": path.resolve(__dirname, "src"),
},
},
提供 mode
配置选项,告知 webpack 使用相应模式的内置优化。
module.exports = {
mode: 'development',
};
默认值为 production
选项 | 描述 |
---|---|
development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development . 为模块和 chunk 启用有效的名。(源码阅读友好) |
production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production 。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin ,FlagIncludedChunksPlugin ,ModuleConcatenationPlugin ,NoEmitOnErrorsPlugin 和 TerserPlugin 。(名称替换、删除注释、换行) |
none | 不使用任何默认优化选项 |
source-map 是一种映射技术,可以根据转换的代码返还成为转化的源代码,这样调试的时候定位到源码中的信息
适用开发环境:
eval
:该模式会把每个 module 封装到 eval 里包裹起来执行,并且会在末尾追加注释 //@ sourceURL
。
此选项会非常快地构建。主要缺点是,由于会映射到转换后的代码,而不是映射到原始代码(没有从 loader 中获取 source map),所以不能正确的显示行数。
eval-source-map
:每个模块使用 eval()
执行,并且 source map 转换为 DataUrl 后添加到 eval()
中。初始化 source map 时比较慢,但是会在重新构建时提供比较快的速度,并且生成实际的文件。行数能够正确映射,因为会映射到原始代码中。它会生成用于开发环境的最佳品质的 source map。
cheap-eval-source-map
:eval-cheap-source-map
- 类似 eval-source-map
,每个模块使用 eval()
执行。这是 " cheap (低开销)" 的 source map ,因为它没有生成列映射 ( column mapping ) ,只是映射行数。它会忽略源自 loader 的 source map,并且仅显示转译后的代码,就像 eval
devtool。
cheap-module-eval-source-map
:类似 eval-cheap-source-map
,并且,在这种情况下,源自 loader 的 source map 会得到更好的处理结果。然而**,loader source map 会被简化为每行一个映射** ( mapping )
适用生产环境:
source-map
:生成 index.js.map 文件,,此文件记录了 source map 行列信息如何映射源代码的信息。它为 bundle 添加了一个引用注释,以便开发工具知道在哪里可以找到它,但是应该将服务器配置为不允许普通用户访问 source map 文件hidden-source-map
:source-map
相同,但不会为 bundle 添加引用注释。如果你只想 source map 映射那些源自错误报告的错误堆栈跟踪信息,但不想为浏览器开发工具暴露你的 source map,这个选项会很有用。nosources-source-map
: 创建的 source map 不包含 sourcesContent(源代码内容)
。它可以用来映射客户端上的堆栈跟踪,而无须暴露所有的源代码。你可以将 source map 文件部署到 web 服务器tips
验证 devtool 名称时,我们期望使用某种模式, 但注意不要混淆 devtool 字符串的顺序, 模式是: [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
.
eval-
: 为每个模块生成 source map 并通过 eval 附加它。建议用于开发,因为改进了重新生成性能。inline-
: 将 source map 内联到原始文件中,而不是创建单独的文件。hidden-
: 没有添加 source map 的引用。source map 没有部署,但仍然应该生成,例如用于错误报告的目的。nosources-
: source map 中不包含源代码。当需要引用原始文件时(需要进一步的配置选项),这可能很有用。修改 package.json 达到传递不同参数调用不同配置的目的
{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"serve": "webpack serve",
"build2": "webpack --config ./config/webpack.common.js --env production",
"serve2": "webpack serve --config ./config/webpack.common.js --env development",
}
}
建立三个分离的配置文件和一个 path 路径文件:
./config/path.js
./config/webpack.common.js
./config/webpack.dev.js
./config/webpack.prod.js
path.js 需匹配到的绝对路径都放在这个文件导出,使用时如 resolveApp('./src')
const path = require("path");
// 从进程的工作目录获取当前目录
const appDir = process.cwd();
const resolveApp = (relativePath) => {
return path.resolve(appDir, relativePath);
};
module.exports = resolveApp;
./config/webpack.common.js
const {merge} = require("webpack-merge");
const prodConfig = require("webpack.prod");
const devConfig = require("webpack.dev");
module.exports = (env) => {
// commonConfig
const commonConfig = {
// entry
// output
// resolve
// module
// plugin 视情况而定 HtmlWebpackPlugin 、 DefinePlugin
};
// 视环境合并config
const isProduction = env.production;
const config = isPtoduction ? prodConfig : devConfig;
return merge(commonConfig, config)
};
./config/webpack.prod.js / ./config/webpack.dev.js 略
module.exports = (env) => {
return {
// mode: "production"
// plugin 视情况而定 CleanWebpackPlugin 、 CopyWebpackPlugin
};
};
建立三个分离的配置文件和一个 path 路径文件:
./config/path.js
./config/webpack.common.js
./config/webpack.dev.js
./config/webpack.prod.js
path.js 需匹配到的绝对路径都放在这个文件导出,使用时如 resolveApp('./src')
const path = require("path");
// 从进程的工作目录获取当前目录
const appDir = process.cwd();
const resolveApp = (relativePath) => {
return path.resolve(appDir, relativePath);
};
module.exports = resolveApp;
./config/webpack.common.js
const {merge} = require("webpack-merge");
const prodConfig = require("webpack.prod");
const devConfig = require("webpack.dev");
module.exports = (env) => {
// commonConfig
const commonConfig = {
// entry
// output
// resolve
// module
// plugin 视情况而定 HtmlWebpackPlugin 、 DefinePlugin
};
// 视环境合并config
const isProduction = env.production;
const config = isPtoduction ? prodConfig : devConfig;
return merge(commonConfig, config)
};
./config/webpack.prod.js / ./config/webpack.dev.js 略
module.exports = (env) => {
return {
// mode: "production"
// plugin 视情况而定 CleanWebpackPlugin 、 CopyWebpackPlugin
};
};