文章内容输出来源:拉勾大前端高薪训练营
- 核心工作原理
- bundle your assets
- 项目中一般会散落着代码及资源文件
- .js
- .html
- .css
- .png
- .json
- .js
- .js
- .jpg
- .css
- .scss
- webpack根据配置找到一个文件作为打包入口
- 一般情况下这个文件就是JS文件
- 然后顺着入口文件的代码,根据代码中出现的import或者像require之类的语句,然后解析推断出来这个文件所依赖的资源模块,然后分别解析每个资源模块所对应的依赖
- 最终形成整个项目所有用到文件依赖关系的依赖树
- 得到依赖树后,webpack会遍历或递归这个依赖树
- 找到每个节点所对应的依赖文件
- 之后根据配置文件中的rules属性找到这个模块所对应的加载器loader
- 然后交给该加载器去加载对这个模块
- 加载的结果放到bundle.js,也就是打包结果当中,从而去实现整个项目的打包
- 整个打包过程中loader机制起了一个更很重要的作用
- Loader机制是webpack的核心
- 没有loader,webpack没法办法实现各种各样资源的加载
- 那么webpack只能算是一个用来去打包或者合并JS模块代码的工具了
- Loader的工作原理
- Loader作为webpack的核心机制,内部工作原理也非常简单
- 开发自己的Loader
- 通过这个过程来深入了解loader的工作原理
- 目标: markdown-loader
- 可以直接在代码中导入markdown文件
- markdown文件一般是被转换为html过后再去呈现到页面上的
- 希望导入markdown文件后得到的结果就是html字符串
- main.js
- import about from './about.md'
console.log(about)
- about.md
- # 关于我
我是时解之,一个渴望涨薪的打工者~
- 项目根目录下新建markdown-loader.js文件
- 内容
- // 每个webpack loader都需要去导出一个函数,函数是对loader所加载到的资源的处理过程
// 参数就是所加载到的资源文件的内容,输出是此次加工后的结果。
module.exports = source ⥤ {
console.log(source)
return ‘hello ~’
}
- 完成后可以考虑发布到npm上作为独立的模块去使用
- 添加加载器的配置
- const path = require ('path')
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: ‘./markdown-loader’
}
]
}
}
- yarn webpack
- 问题: Module parse failed:Unexpected token
- 建议: you may need an additional loader to handle the result of these loaders.
- 问题原因
- markdown-loader定义中返回的hello字符串不是一个标准的JS代码,所以才会出现这个问题
- 解决办法
- 要么markdown-loader返回标准的JS代码
- // 每个webpack loader都需要去导出一个函数,函数是对loader所加载到的资源的处理过程
// 参数就是所加载到的资源文件的内容,输出是此次加工后的结果。
module.exports = source ⥤ {
console.log(source)
return ‘console.log(“hello ~”)’
}
- yarn webpack
- Ok~
- 看下打包过后的结果bundle.js
- 找到最后一个模块
- webpack打包的时候就是把刚刚loader打包的结果也就是返回的那个字符串直接拼接到这个模块当中了
- 这也解释了loader管道最后必须返回JS代码的原因
- 如果随便返回一个内容的话,拼接到模块中时可能语法不通过
- yarn add marked --dev
- // 每个webpack loader都需要去导出一个函数,函数是对loader所加载到的资源的处理过程
// 参数就是所加载到的资源文件的内容,输出是此次加工后的结果。
const marked = require (‘marked’)
module.exports = source ⥤ {
// console.log(source)
// return ‘console.log(“hello ~”)’
const html = marked(source)
return module.exports = ${JASON.Stringify(html)}
}
- yarn webpack
- OK~
- 看打包结果
- OK~
- 支持以ES Modules导出
- // 每个webpack loader都需要去导出一个函数,函数是对loader所加载到的资源的处理过程
// 参数就是所加载到的资源文件的内容,输出是此次加工后的结果。
const marked = require (‘marked’)
module.exports = source ⥤ {
// console.log(source)
// return ‘console.log(“hello ~”)’
const html = marked(source)
return export default ${JASON.Stringify(html)}
}
- yarn webpack
- OK~
- 看打包结果
- OK~
- 要么使用额外的loader接着去处理markdown-loader返回的结果
- markdown-loader返回html 字符串 交给下一个 loader处理
- // 每个webpack loader都需要去导出一个函数,函数是对loader所加载到的资源的处理过程
// 参数就是所加载到的资源文件的内容,输出是此次加工后的结果。
module.exports = source ⥤ {
// console.log(source)
// return ‘console.log(“hello ~”)’
const html = marked(source)
return html
}
- const path = require (‘path’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
}
}
- yarn webpack
- OK~
- 看打包结果
- OK~
- Webpack加载资源的过程类似于管道,你可以在这个过程中依次去使用多个loader
- 但是要求最终这个管道工作过后的结果必须是一段JS代码
- Loader负责资源文件从输入到输出的转换
- 对于同一个资源可以依次使用多个Loader
- 例如样式资源文件的处理是从css-loader ⥤ style-loader
- 插件机制
- 作用
- webpack中另外一个核心特性
- 目的是为了增强webpack自动化能力
- Loader专注实现各种各样资源模块加载,从而实现整体项目的打包
- Plugin解决除了资源加载以外其他的自动化工作
- 例如
- 清除dist目录
- 拷贝静态文件到输出目录
- 压缩输出代码
- webpack+plugin 实现了绝大多数前端工程化工作
- 这也正是很多初学者认为webpack就是前端工程化的这种理解的原因
- 常用插件
- clean-webpack-plugin
- 自动清除输出目录插件
- yarn add clean-webpack-plugin --dev
- 修改配置文件webpack.config.js
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin()
]
}
- yarn webpack
- OK~
- 看打包结果
- OK~
- html-webpack-plugin
- 自动生成使用打包结果的html
- 通过webpack输出HTML文件
- yarn add html-webpack-plugin --dev
- 修改配置文件webpack.config.js
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
}
})
]
}
- yarn webpack
- OK~
- 看打包结果
- OK~
- 模板方式使用
- src目录下新增index.html
- <DOCTYPE html>
<h1><%= htmlWebpackPlugin.options.title %></h1>
</div>
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
})
]
}
- yarn webpack
- OK~
- 看打包结果
- OK~
- 多实例
- 同时输出多个页面文件
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
// 用于生成 index.html文件
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
}) ,
// 用于生成 about.html文件
new HtmlWebpackPlugin({
// 设置生成html的文件名称,默认为index.html
filename: ‘about.html’,
})
]
}
- yarn webpack
- OK: 同时生成了index.html与about.html
- copy-webpack-plugin
- yarn add copy-webpack-plugin --dev
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
const CopyWebpackPlugin = require (‘copy-webpack-plugin’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
// 用于生成 index.html文件
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
}) ,
// 用于生成 about.html文件
new HtmlWebpackPlugin({
// 设置生成html的文件名称,默认为index.html
filename: ‘about.html’,
}) ,
// 用于拷贝资源文件
new CopyWebpackPlugin([
// 支持通配符
// ‘public/**’,
// 也支持相对路径
‘public’,
])
]
}
- yarn webpack
- OK~
- webpack社区还提供了很多插件
- 不用全部都提前知道
- 需要时: 需求⥤ 关键词 ⥤ 搜索 即可
- 工作原理
- 相比于loader, plugin拥有更宽的能力范围
- Loader只是在加载模块的环节去工作
- 插件plugin的作用范围几乎可以触及到webpack工作的每一个环节
- webpack的插件机制是如何实现的?
- 利用了软件开发中最常见到的钩子机制
- Plugin通过钩子机制实现
- 钩子机制有点类似于web中的事件
- 在webpack工作的过程中会有很多环节,为了便于插件的扩展,webpack几乎给每一个环节都埋下了一个钩子
- 在开发插件时,只需给这些不同的钩子挂载不同的任务就可以轻松的扩展webpack的能力
- 具体有哪些预定义的钩子,详见webpack官方文档
- 开发自定义插件
- webpack要求我们的插件必须是一个函数或者包含apply方法的对象
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
const CopyWebpackPlugin = require (‘copy-webpack-plugin’)
class MyPlugin {
// webpack启动时会自动调用此方法。参数compiler是webpack工作过程中最核心的一个对象。
// 此对象中包含了此次构建的所有配置信息,也是通过这个对象注册钩子函数。
apply(compiler) {
console.log(‘MyPlugin 启动’)
compiler.hooks.emit.tap('MyPlugin', compilation ⥤ {
// compilation: 可以理解为此次打包的上下文
for (const name in compilation.assets) {
// console.log(name)
// console.log(compilation.assets[name].sourse())
if (name.endsWith('.js')) {
const contents = compilation.assets[name].sourse()
const withoutComment = contents.replace(/\/\*\*+\*\//g, '')
compilation.assets[name] = {
source:() ⥤ withoutComments,
size: ()⥤withoutComments.length
}
}
}
})
}
}
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
// 用于生成 index.html文件
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
}) ,
// 用于生成 about.html文件
new HtmlWebpackPlugin({
// 设置生成html的文件名称,默认为index.html
filename: ‘about.html’,
}) ,
// 用于拷贝资源文件
new CopyWebpackPlugin([
// 支持通配符
// ‘public/**’,
// 也支持相对路径
‘public’,
]) ,
// 自定义插件
new MyPlugin()
]
}
- yarn webpack
- OK~
- 插件是通过在生命周期的钩子中挂载函数实现扩展
$$
$$
- 开发体验的设想
- 编写源代码
- webpack打包
- 运行应用
- 刷新浏览器
- 设想:理想的开发环境
- Idea1: 以Http Server运行
- Idea2: 自动编译+自动刷新
- Idea3: 提供source map支持
- 如何增强webpack开发体验
- 实现自动编译打包
- 使用webpack-cli提供的watch工作模式
- 监听文件变化,自动重新打包
- yarn webpack --watch
- 希望编译过后自动刷新浏览器
- BrowserSync
- yarn global add browser-sync
- browser-sync dist --files "**/*"
- 弊端
- 操作上太麻烦了,需要同时使用两个工具
- 开发效率降低了
- webpack会不断地将文件写入磁盘,browser-sync也会及时从磁盘读取
- 有待继续改善开发体验
- webpack dev server
- webpack官方推出的开发工具
- 提供用于开发的http server
- 集成自动编译和自动刷新浏览器等功能
- 使用
- yarn add webpack-dev-server --dev
- yarn webpack-dev-server
- 为了提高工作效率,webpack-dev-server 将打包结果存放于内存当中
- yarn webpack-dev-server --open
- 自动打开浏览器
- 静态资源访问
- Dev Server默认只会serve打包输出文件
- 只要是webpack输出的文件,都可以正常被访问到
- 若其他静态资源文件也需要serve
- 需要额外告知webpack-dev-server
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
const CopyWebpackPlugin = require (‘copy-webpack-plugin’)
class MyPlugin {
// webpack启动时会自动调用此方法。参数compiler是webpack工作过程中最核心的一个对象。
// 此对象中包含了此次构建的所有配置信息,也是通过这个对象注册钩子函数。
apply(compiler) {
console.log(‘MyPlugin 启动’)
compiler.hooks.emit.tap('MyPlugin', compilation ⥤ {
// compilation: 可以理解为此次打包的上下文
for (const name in compilation.assets) {
// console.log(name)
// console.log(compilation.assets[name].sourse())
if (name.endsWith('.js')) {
const contents = compilation.assets[name].sourse()
const withoutComment = contents.replace(/\/\*\*+\*\//g, '')
compilation.assets[name] = {
source:() ⥤ withoutComments,
size: ()⥤withoutComments.length
}
}
}
})
}
}
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
// 专门用于webpack-dev-server做选项配置的
devServer: {
// 额外为开发服务器指定查找资源目录
contentBase: ‘./public’
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
// 用于生成 index.html文件
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
}) ,
// 用于生成 about.html文件
new HtmlWebpackPlugin({
// 设置生成html的文件名称,默认为index.html
filename: ‘about.html’,
}) ,
// 用于拷贝资源文件。在开发阶段最好不要使用这个插件。
// 开发中会频繁执行打包任务,假设如果拷贝的文件较多或比较大。
// 每次执行开销较大,并且打包速度也会降低。建议打生产包时再放开使用
//new CopyWebpackPlugin([
// 支持通配符
// ‘public/**’,
// 也支持相对路径
// ‘public’,
//]) ,
// 自定义插件
new MyPlugin()
]
}
- yarn webpack
- Ok~
- 代理Api服务
- 本地环境
- http://localhost:8080/index.html ⥤ https://www.example.com/api/users
- 跨域资源共享(CORS)
- 使用CORS的前提是API必须支持
- 并不是任何情况下API都应该支持
- 同源部署
- 开发阶段接口跨域问题
- 浏览器 ⥤ API服务器
- 存在跨域问题
- 浏览器 ⥤ 开发服务器 ⥤ API服务器
- Ok~
- webpack-dev-server支持配置代理
- 目标
- 将GitHub API 代理到开发服务器
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
const CopyWebpackPlugin = require (‘copy-webpack-plugin’)
class MyPlugin {
// webpack启动时会自动调用此方法。参数compiler是webpack工作过程中最核心的一个对象。
// 此对象中包含了此次构建的所有配置信息,也是通过这个对象注册钩子函数。
apply(compiler) {
console.log(‘MyPlugin 启动’)
compiler.hooks.emit.tap('MyPlugin', compilation ⥤ {
// compilation: 可以理解为此次打包的上下文
for (const name in compilation.assets) {
// console.log(name)
// console.log(compilation.assets[name].sourse())
if (name.endsWith('.js')) {
const contents = compilation.assets[name].sourse()
const withoutComment = contents.replace(/\/\*\*+\*\//g, '')
compilation.assets[name] = {
source:() ⥤ withoutComments,
size: ()⥤withoutComments.length
}
}
}
})
}
}
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
// 专门用于webpack-dev-server做选项配置的
devServer: {
// 额外为开发服务器指定查找资源目录
contentBase: ‘./public’,
proxy: {
‘/api’: {
// http://localhost:8080/api/users ⥤ https://api.github.com/api/users
target: ‘https://api.github.com’,
// http://localhost:8080/api/users ⥤ https://api.github.com/users
pathRewrite: {
‘^/api’: ‘’
},
// 不能使用localhost:8080 作为请求 GitHub的主机名
changeOrigin: true
}
}
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
// 用于生成 index.html文件
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
}) ,
// 用于生成 about.html文件
new HtmlWebpackPlugin({
// 设置生成html的文件名称,默认为index.html
filename: ‘about.html’,
}) ,
// 用于拷贝资源文件。在开发阶段最好不要使用这个插件。
// 开发中会频繁执行打包任务,假设如果拷贝的文件较多或比较大。
// 每次执行开销较大,并且打包速度也会降低。建议打生产包时再放开使用
//new CopyWebpackPlugin([
// 支持通配符
// ‘public/**’,
// 也支持相对路径
// ‘public’,
//]) ,
// 自定义插件
new MyPlugin()
]
}
- yarn webpack-dev-server
- 生产环境
- http://www.example.com/index.html ⥤ https://www.example.com/api/users
- Source Map
- 源代码地图
- 用于映射转换后的代码与源代码的关系
- map文件内容解析
- version
- 当前文件所使用的source map标准的版本
- sources
- 记录转换之前源文件的名称
- names
- 源代码中使用的一些成员名称
- mappings
- 整个source-map文件的核心属性
- base64/vlq编码的字符串
- 字符串记录的信息就是转换过后代码的字符,与转换之前所对应的映射关系
- jquery手动添加
- //# sourceMapingURL = jquey-3.4.1.min.map
- 作用
- 解决了源代码与运行代码不一致所产生的问题
- webpack配置source map
- const path = require ('path')
const { CleanWebpackPlugin }= require (‘clean-webpack-plugin’)
const HtmlWebpackPlugin = require (‘html-webpack-plugin’)
const CopyWebpackPlugin = require (‘copy-webpack-plugin’)
module.exports = {
mode: ‘none’,
// 指定webpack打包的入口路径,指定相对路径时,’./'不能省略
entry: ‘./src/main.js’,
// 设置输出文件的位置
output: {
// 设置输出文件名称
filename: ‘bundle.js’,
// 指定输出文件所在目录,不可使用相对路径
path: path.join(__dirname,‘output’)
// 默认值是个空字符串:代表网站的根目录。这里的/线不能省略
// publicPath: ‘dist/’,
},
//用于配置开发过程中的辅助工具。也就是与source-map功能相关的配置
devtool: ‘source-map’
// 专门用于webpack-dev-server做选项配置的
devServer: {
// 额外为开发服务器指定查找资源目录
contentBase: ‘./public’,
proxy: {
‘/api’: {
// http://localhost:8080/api/users ⥤ https://api.github.com/api/users
target: ‘https://api.github.com’,
// http://localhost:8080/api/users ⥤ https://api.github.com/users
pathRewrite: {
‘^/api’: ‘’
},
// 不能使用localhost:8080 作为请求 GitHub的主机名
changeOrigin: true
}
}
},
module: {
// 针对于其他资源模块的加载规则的配置
rules: [
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 198: …] }̲, …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: {
loader: ‘url-loader’,
options: {
limit: 10 * 1024, // 10KB,url-loader只将10KB以下的文件转换为Data URL形式,超过此大小的仍然交给file-loader完成加载
}
}
} ,
// 每个规则对象都需要配置两个属性: test和use
{
// 正则表达式,用于匹配我们在打包过程中所遇到的文件路径
test: /.htmlKaTeX parse error: Expected 'EOF', got '}' at position 171: …} }̲ , …/,
// 用来指定test匹配到的文件需要使用的loader,配置多个loader时执行顺序是从后往前执行
use: [
‘html-loader’,
‘./markdown-loader’,
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
// 用于生成 index.html文件
new HtmlWebpackPlugin({
// 指定自动生成的html的标题
title: ‘Webpack Plugin Sample’,
// 设置元数据标签
meta: {
viewport: ‘width=device-width’
},
// 指定自动生成的html的模板文件
template: ‘./src/index.html’,
}) ,
// 用于生成 about.html文件
new HtmlWebpackPlugin({
// 设置生成html的文件名称,默认为index.html
filename: ‘about.html’,
}) ,
// 用于拷贝资源文件。在开发阶段最好不要使用这个插件。
// 开发中会频繁执行打包任务,假设如果拷贝的文件较多或比较大。
// 每次执行开销较大,并且打包速度也会降低。建议打生产包时再放开使用
//new CopyWebpackPlugin([
// 支持通配符
// ‘public/**’,
// 也支持相对路径
// ‘public’,
//]) ,
]
}
- webpack支持12种不同的方式
- 每种方式的效率和效果各不相同
- devtool
- eval
- eval('console.log(123) //# sourceURL=./foo/bar'
- 未生成source-map文件
- 构建速度最快的
- 只能定位源代码名称
- eval-source-map
- 同eval模式,也是使用eval函数执行模块代码
- 可以具体定位到行和列信息
- 生成了source-map文件
- cheap-eval-source-map
- 同eval模式,也是使用eval函数执行模块代码
- 可以具体定位到源代码行
- 生成了source-map文件
- 调试时定位到的代码是转换后的代码
- cheap-module-eval-source-map
- 同eval模式,也是使用eval函数执行模块代码
- 可以具体定位到源代码行
- 生成了source-map文件
- 调试时定位到的代码跟跟编写的代码一致,未做新特性转换
- inline-source-map
- source-map信息内嵌到打包文件中最后位置
- 一般不会使用,因为导致打包结果文件变得很大
- hidden-source-map
- 生成了source-map文件,但是不可见
- 主要用于开发第三方包时使用
- nosources-source-map
- 可以看到错误出现的位置,但是点击错误信息进去后看不见代码
- 提供了行信息,但看不见源代码
- source-map命名规律
- eval
- 是否使用eval执行模块代码
- cheap
- Source Map是否只包含行信息
- module
- 是否能够得到Loader处理之前的源代码
- 选择合适的source-map
- 参考
- 开发模式
- 选cheap-module-eval-source-map
- 选择条件参考
- 每行代码不会超过80个字符
- 经过Loader转换后的代码与源代码差异较大
- 首次打包慢无所谓,重写打包相对较快
- 配置:devtool: cheap-module-eval-source-map'
- 生产模式
- 选none
- 原因参考
- Source Map会暴露源代码
- 调试是开发阶段的事
- 配置: 'none'
- 备选nosources-source-map
- 理解不同模式差异,适配不同的环境