webpack
工作模式
webpack.js.org/configurati…
用法
mode在配置中提供选项:
module.exports = {
mode: 'development'
};
或将其作为CLI参数传递:
webpack --mode=development
开发模式
// webpack.development.config.js
module.exports = {
+ mode: 'development'
- devtool: 'eval',
- cache: true,
- performance: {
- hints: false
- },
- output: {
- pathinfo: true
- },
- optimization: {
- moduleIds: 'named',
- chunkIds: 'named',
- mangleExports: false,
- nodeEnv: 'development',
- flagIncludedChunks: false,
- occurrenceOrder: false,
- concatenateModules: false,
- splitChunks: {
- hidePathInfo: false,
- minSize: 10000,
- maxAsyncRequests: Infinity,
- maxInitialRequests: Infinity,
- },
- emitOnErrors: true,
- checkWasmTypes: false,
- minimize: false,
- removeAvailableModules: false
- },
- plugins: [
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
生产模式
// webpack.production.config.js
module.exports = {
+ mode: 'production',
- performance: {
- hints: 'warning'
- },
- output: {
- pathinfo: false
- },
- optimization: {
- moduleIds: 'deterministic',
- chunkIds: 'deterministic',
- mangleExports: 'deterministic',
- nodeEnv: 'production',
- flagIncludedChunks: true,
- occurrenceOrder: true,
- concatenateModules: true,
- splitChunks: {
- hidePathInfo: true,
- minSize: 30000,
- maxAsyncRequests: 5,
- maxInitialRequests: 3,
- },
- emitOnErrors: false,
- checkWasmTypes: true,
- minimize: true,
- },
- plugins: [
- new TerserPlugin(/* ... */),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
- new webpack.optimize.ModuleConcatenationPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ]
}
none模式
// webpack.custom.config.js
module.exports = {
+ mode: 'none',
- performance: {
- hints: false
- },
- optimization: {
- flagIncludedChunks: false,
- occurrenceOrder: false,
- concatenateModules: false,
- splitChunks: {
- hidePathInfo: false,
- minSize: 10000,
- maxAsyncRequests: Infinity,
- maxInitialRequests: Infinity,
- },
- emitOnErrors: true,
- checkWasmTypes: false,
- minimize: false,
- },
- plugins: []
}
根据webpack.config.js中的mode变量更改行为
var config = {
entry: './app.js'
//...
};
module.exports = (env, argv) => {
if (argv.mode === 'development') {
config.devtool = 'source-map';
}
if (argv.mode === 'production') {
//...
}
return config;
};
loader
编译转换类
css-loader
babel-loader
webpack需要完成模块打包,默认会转换es6的import、export;对于箭头函数、const等es6语法则不处理。
// webpack.config.js
module: {
rules: [
{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
添加babel-loader并配置转换规则后,const声明和箭头函数被转换成var以及普通函数,如下图:
文件操作类
file-loader
style-loader
url-loader
适合体积比较小的资源,减少请求发送次数;较大文件通过文件方式加载,提高页面加载速度
// 当资源文件小于10kb就会通过base64编码方式引入资源;大于10kb的话,url-loader会在内部调用file-loader引入资源,所以使用了以下配置项,必须安装file-loader
{
test: /.jpg/,
use: [
{
loader: 'url-loader',
options: {
limit: 10 * 1024 // 10kb
}
}
]
}
代码检查类
加载资源的方式
ES module 的 import
遵循Commonjs标准的require函数
遵循AMD标准的define和require函数
loader加载非js的资源
css中的@import指令和url函数
如下图例子,css中通过@import指令引入heading.css样式文件,heading.css中通过url函数引入背景图片。
/* main.css */
@import './heading.css';
body {
font-size: 20px;
}
/* heading.css */
.heading {
background-color: gray;
background-image: url(./avatar.jpg);
}
// webpack.config.js
module: {
rules: [
...
{
test: /.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /.jpg$/,
use: [
{
loader: "url-loader",
options: {
limit: 10 * 1024, // 10kb
}
}
]
}
]
}
html中的资源加载
// main.js
import footerHtml from './footer.html'
document.write(footerHtml);
<!-- footer.html -->
<footer>
<a href="./wall.jpg">跳转wall图片</a>
<img src="./avatar.jpg">
</footer>
// webpack.config.js
// html-loader v0.5.5版本及以下
{
test: /.html$/,
use: {
loader: "html-loader",
options: {
attrs: ["img:src", "a:href"] // 默认为 attrs: ['img:src']
}
}
}
// html-loader v1.0.0版本以上
{
test: /.html$/,
use: {
loader: "html-loader",
options: {
attributes: {
list: [
// All default supported tags and attributes
"...",
{
tag: "a",
attribute: "href",
type: "src",
}
]
}
}
}
}
自定义loader
1、对于同一份资源,可以采用多个loader处理 1、每个loader都必须导出一个函数 2、经过多个loader处理后,最后返回的结果必须是一段标准的JavaScript代码
实现1
// webpack.config.js
const path = require('path')
module.exports = {
mode: 'none',
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist'),
publicPath: 'dist/'
},
module: {
rules: [
{
test: /.md$/,
use: {
loader: './md-loader.js'
}
}
]
}
}
// main.js
import about from './about.md'
console.log(about)
// about.md
## md-loader
md-loader.js
// 写法1
module.exports = source => {
return source
}
// 写法2
module.exports = source => {
return `console.log("md-loader")`
}
// 正确写法,CommonJS
module.exports = source => {
return `module.exports = ${JSON.stringify(source)}`
}
// 正确写法,ES Module
module.exports = source => {
return `export default ${JSON.stringify(source)}`
}
采用第一种写法,直接在函数返回source,会提示打包错误:"You may need an additional loader to handle the result of these loaders."。因为最终结果必须是标准的javascript代码
打包后的bundle.js
采用第二种写法,在函数内返回javascript代码的结果如下:
可以看到"console.log(1)"被直接放到函数内
由于我们需要把md文件的内容模块化导出,所以导出的内容需要采用CommonJS或ES Module的标准返回,并且为了能够把md文件内容转化为html,引入"marked"模块进行处理。
// CommonJS
const marked = require('marked')
module.exports = source => {
const html = marked(source)
return `module.exports = ${JSON.stringify(html)}`
}
输出
// ES Module
const marked = require('marked')
module.exports = source => {
const html = marked(source)
return `export default ${JSON.stringify(html)}`
}
输出
实现2
通过md-loader将md文件转换成html,再通过html-loader处理,生成标准的javascript代码
// webpack.config.js
const path = require('path')
module.exports = {
mode: "none",
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.join(__dirname, "dist"),
publicPath: "dist/",
},
module: {
rules: [
{
test: /.md$/,
use: ["html-loader", "./md-loader.js"]
},
],
},
};
// md-loader.js
const marked = require('marked')
module.exports = source => {
const html = marked(source)
// 直接返回html给下一个loader(html-loader)
return html;
}
输出
plugin
clean-webpack-plugin
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
plugins: [new CleanWebpackPlugin()]
}
html-webpack-plugin
硬编码对应的问题
- 发布代码需要同时发布根目录下的index.html和dist目录中的资源,相对麻烦
- 需要手动维护index.html中资源引用路径(webpack bundle文件名中包含的哈希值随着编译而发生变化)
单页面
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 使用lodash模板语法读取变量值 -->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<!-- 此处并不需要引入main.js,Html-webpack-plugin只是把index.html当做一个模板文件,不会根据它分析文件依赖关系 -->
<!-- <script src="src/main.js" type="module"></script> -->
</body>
</html>
// webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: "none",
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.join(__dirname, "dist")
- publicPath: "dist/",
},
module: {
rules: [
{
test: /.html$/,
+ exclude: [require.resolve("./index.html")], // 需要排除掉index.html,否则lodash模板语法不会生效
use: {
loader: "html-loader",
options: {
attributes: {
list: [
// All default supported tags and attributes
"...",
{
tag: "a",
attribute: "href",
type: "src",
},
],
},
},
},
},
{
test: /.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /.jpg$/,
use: [
{
loader: "url-loader",
options: {
limit: 10 * 1024, // 10kb
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
+ new HtmlWebpackPlugin({
+ title: "网页标题",
+ meta: {
+ viewport: "width=device-width",
+ },
+ template: "./index.html",
+ }),
]
}
多页面
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "网页标题",
meta: {
viewport: "width=device-width",
},
template: "./index.html",
}),
new HtmlWebpackPlugin({
filename: 'about.html'
})
]
思考题
有了解过 webpack 源码吗?
webpack import 打包后的结果是怎样的?
webpack 用过吗?打包原理是怎么样的?用过什么打包工具?
webpack插件和loader的区别
webpack性能优化
loader实现机制和原理
有没有看过一些源码,整理的webpack项目有什么难点,怎么进行优化的
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!