”你负责开发,我负责打包”系列三

文章内容输出来源:拉勾大前端高薪训练营

- 核心工作原理

- 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>
Webpacks
<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

			- 理解不同模式差异,适配不同的环境
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值