模块化是一种主流的组织方式,它经过把咱们的复杂代码按照功能的不一样划分为不一样的模块,单独的维护这种方式,提升咱们的开发效率,下降维护成本。javascript
模块化只是思想,不包含具体的实现。css
CommonJS in Node.jshtml
Es Modules in Browers前端
CommonJSvue
ES Modulesjava
ESM中没有CommonJS中的那些模块全局变量node
webpack做为目前最主流的前端模块打包器,提供了一整套前端项目模块化方案。react
webpack4之后的版本它支持零配置的方式直接启动打包,打包过程会按照约定src/index.js
=>dist/main.js
jquery
const path = require('path')
module.exports = {
//去指定webpack打包入口文件的路径
entry: './src/main.js',
//设置输出文件的配置
output: {
//输出文件的名称
filename: 'bundle.js',
//输出文件的路径(绝对路径)
path: path.join(__dirname, 'dist')
}
}
复制代码
webpack4新增工做模式作法,这种用法大大的简化了webpack配置的复杂程度,能够把它理解成针对于不一样环境的几组预设配置webpack
module.exports = {
//工做模式
mode: 'development'
}
复制代码
总体生成的代码是一个当即执行的函数,这个函数接受一个modules的参数,调用时传入了一个数组
展开这个数组,数组中的每个元素都是一个参数列表相同的函数,这里的函数对于的是源代码当中的模块,每个模块最终都会包裹到这些函数当中,从而实现模块的私有做用域
Loader是Webpack的核心特性,借助于Loader就能够加载任何类型的资源。
以加载css为例,首先安装css-loader来转换css文件,在安装style-loader将css-loader转换事后的结果经过style标签的形式添加到页面上,webpack配置以下:
// 配置对象
module: {
//其余资源模块加载规则
rules: [{
//匹配打包过程当中遇到的文件路径
test: /.css$/,
//匹配文件打包过程当中用的loader 配置了多个loader执行顺序是从后往前执行
use: [
'style-loader', //把css-loader转换后的结果经过style标签的形式添加到页面上
'css-loader' //处理css文件的加载器
]
}]
}
复制代码
webpack的打包入口通常是javascript文件,通常打包入口是应用程序的运行入口,目前而言,前端应用中的业务是由JavaScript来驱动的。
import './heading.css'
export default () => {
const element = document.createElement('h2')
element.textContent = 'Hello world'
element.classList.add('heading')
element.addEventListener('click', () => {
alert('Hello webpack')
})
return element
}
复制代码
file-loader 处理文件加载器
文件加载器的工做过程
webpack在打包时遇到咱们的图片文件,根据咱们配置文件当中的配置匹配到对应的文件加载器,此时文件加载器开始工做,它先将咱们导入的文件拷贝到输出目录,而后将输出目录的路径做为当前模块的返回值返回,这样对于咱们的应用来讲所须要的资源就被发布出来了,同时咱们能够经过模块的导出成员拿到咱们资源的访问路径
{
test: /.png$/,
use: 'file-loader' //文件加载器
}
复制代码
Data URIs是一种当前URL就能表示文件内容的方式,这种URL中的文本就已经包含了文件内容,咱们在使用这种URL的时候就不会去发送任何的HTTP请求
url-loader Data URI加载器
{
test: /.png$/,
use: 'url-loader', //Data URLs加载器
//配置选项
options: {
limit: 10 * 1024 // 只将10kb如下的文件用url-loader处理
}
}
复制代码
最佳实践
注意事项:对于超出大小的文件url loader会去调用file loader,因此仍是要安装fileloader
webpack的资源加载器相似生活当中工厂里面的生产车间,它是用来处理和加工打包过程看成的资源文件
因为webpack默认就能处理咱们代码当中的import/export,因此很天然的有人认为webpack会自动编译es6的代码,由于模块打包须要,因此处理import/export,除此以外并不能处理代码当中其余的es6特性,若是咱们须要在打包过程看成处理其余es6特性的转换,咱们须要为js文件添加一个额外的编译性loader
babel-loader,一个编译型loader,用来处理es6特性的转换
{
test: /.js$/,
use: {
loader: 'babel-loader', //处理es6代码看成的新特性
options: {
//babel只是一个转换js代码的平台,在平台转换过程当中须要额外的插件
presets: ['@babel/preset-env']
}
}
}
复制代码
webpack只是打包工具
加载器能够用来编译转换代码
{
test: /.html$/,
use: {
loader: 'html-loader', //html解析器
options: {
// html加载的时候对页面上的一些属性作一些额外处理
attrs: [
'img:src', //默认
'a:href'
]
}
}
}
复制代码
markdown-loader 在代码当中直接导入markdown文件
实现方式
const marked = require('marked') //markdown解析模块
module.exports = source => {
const html = marked(source)
//返回的类型必定要是js代码
// return 'console.log("hello ~")'
//直接拼接html当中存在的换行符和内部的引号拼接在一块儿可能引发语法错误
// return `module.exports="${html}"`
//CommonJS方式导出字符串
// return `module.exports=${JSON.stringify(html)}`
//ES Modules方式导出
// return `export default ${JSON.stringify(html)}`
//返回html字符串交给下一个loader处理
return html
}
复制代码
{
test: /.md$/,
use: [
'html-loader',
'./markdown-loader'
]
}
复制代码
工做原理
//配置插件
plugins: [
//清理输出目录
new CleanWebpackPlugin()
]
复制代码
//配置插件
plugins: [
//清理输出目录
new CleanWebpackPlugin(),
//自动生成index.html
new HtmlWebpackPlugin({
title: 'Webpack Plugin Sample',
meta: {
viewport: 'width=device-width'
},
template: './index.html'
}),
//用于生成about.html
new HtmlWebpackPlugin({
filename: 'about.html'
})
]
复制代码
class MyPlugin {
apply(compiler) {
console.log('My Plugin 启动')
compiler.hooks.emit.tap('MyPlugin', compilation => {
//compilation能够理解为这次打包的上下文
for (const name in compilation.assets) {
// console.log(compilation.assets[name].source())
//判断是不是js文件
if (name.endsWith('.js')) {
//获取文件的内容
const contents = compilation.assets[name].source()
//将注释替换成空
const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
//将最终结果覆盖原有的内容当中
compilation.assets[name] = {
//返回新的内容
source: () => withoutComments,
//返回内容大小,这个方式是webpack内部要求必须的方法
size: () => withoutComments.length
}
}
}
})
}
}
复制代码
//配置插件
plugins: [
//自定义插件 删除生成的js文件当中的注释
new MyPlugin()
]
复制代码
跨域资源共享(CORS),使用CORS的前提是API必须支持,并非任何状况下API都应该支持
同源部署(域名端口协议一致)
开发阶段接口跨域
webpack dev server支持配置代理
用法
// 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
//代理路径重写
publicPath: {
'^/api': ''
},
//不能使用 localhost:8080 做为请求 github 的主机名
changeOrigin: true //以实际代理请求的主机名去请求
}
}
}
复制代码
//配置开发过程当中的辅助工具
devtool: 'source-map'
复制代码
devtool | 构建速度 | 从新构建速度 | 生产环境 | 品质(quality) |
(none) | 很是快速 | 很是快速 | yes | 打包后的代码 |
eval | 很是快速 | 很是快速 | no | 生成后的代码 |
eval-cheap-source-map | 比较快 | 快速 | no | 转换过的代码(仅限行) |
eval-cheap-module-source-map | 中等 | 快速 | no | 原始源代码(仅限行) |
eval-source-map | 慢 | 比较快 | no | 原始源代码 |
eval-nosources-source-map | ||||
eval-nosources-cheap-source-map | ||||
eval-nosources-cheap-module-source-map | ||||
cheap-source-map | 比较快 | 中等 | yes | 转换过的代码(仅限行) |
cheap-module-source-map | 中等 | 比较慢 | yes | 原始源代码(仅限行) |
inline-cheap-source-map | 比较快 | 中等 | no | 转换过的代码(仅限行) |
inline-cheap-module-source-map | 中等 | 比较慢 | no | 原始源代码(仅限行) |
inline-source-map | 慢 | 慢 | no | 原始源代码 |
inline-nosources-source-map | ||||
inline-nosources-cheap-source-map | ||||
inline-nosources-cheap-module-source-map | ||||
source-map | 慢 | 慢 | yes | 原始源代码 |
hidden-source-map | 慢 | 慢 | yes | 原始源代码 |
hidden-nosources-source-map | ||||
hidden-nosources-cheap-source-map | ||||
hidden-nosources-cheap-module-source-map | ||||
hidden-cheap-source-map | ||||
hidden-cheap-module-source-map | ||||
nosources-source-map | 慢 | 慢 | yes | 无源代码内容 |
nosources-cheap-source-map | ||||
nosources-cheap-module-source-map |
HMR集成在webpack-dev-server中
//热更新插件
new webpack.HotModuleReplacementPlugin()
复制代码
module.hot.accept('./editor', () => {
console.log('editor模块更新了,须要这里手动处理热更新')
})
复制代码
//存储最后一次更新的值
let lastEditor = editor
module.hot.accept('./editor', () => {
console.log('editor模块更新了,须要这里手动处理热更新', lastEditor.value)
//拿到编辑的内容
const value = lastEditor.value
//移除原来的元素
document.body.removeChild(editor)
//建立一个新的元素
const newEditor = createEditor()
//将原来的只添加到新元素的值当中 避免原来的值丢失
newEditor.value = value
//将新元素追加到页面
document.body.appendChild(newEditor)
//记录最新的元素 不然下次找不到这个元素了
lastEditor = newEditor
})
复制代码
//图片的热处理替换
module.hot.accept('./01.png', () => {
img.src = background
console.log(background)
})
复制代码
/** * 不一样的环境返回不一样的配置 * @param {*} env CLI传递的环境名参数 * @param {*} argv 运行CLI过程当中所传递的全部参数 */
module.exports = (env, argv) => {
//开发环境的配置
const config = {
//工做模式
mode: 'none',
//去指定webpack打包入口文件的路径
entry: './src/main.js',
//设置输出文件的配置
output: {
//输出文件的名称
filename: 'bundle.js',
//输出文件的路径(绝对路径)
path: path.join(__dirname, 'dist'),
//打包事后的文件具体存放位置
// publicPath: 'dist/'
},
// webpack dev server的配置选项
devServer: {
//开启热更新 报错会从新刷新浏览器,不易调试
hot: true,
//不管代码是否被处理了热替换,浏览器都不会自动刷新
hotOnly: true,
//静态资源文件路径
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
//代理路径重写
publicPath: {
'^/api': ''
},
//不能使用 localhost:8080 做为请求 github 的主机名
changeOrigin: true //以实际代理请求的主机名去请求
}
}
},
//配置开发过程当中的辅助工具
devtool: 'eval',
// 配置对象
module: {
//其余资源模块加载规则
rules: [{
//匹配打包过程当中遇到的文件路径
test: /.css$/,
//匹配文件打包过程当中用的loader 配置了多个loader执行顺序是从后往前执行
use: [
'style-loader', //把css-loader转换后的结果经过style标签的形式添加到页面上
'css-loader' //处理css文件的加载器
]
},
{
test: /.png$/,
use: {
loader: 'url-loader', //Data URLs加载器
//配置选项
options: {
limit: 10 * 1024 // 只将10kb如下的文件用url-loader处理
}
}
}, {
test: /.html$/,
use: {
loader: 'html-loader', //html解析器
options: {
// html加载的时候对页面上的一些属性作一些额外处理
attrs: [
'img:src', //默认
'a:href'
]
}
}
}, {
test: /.md$/,
use: [
'html-loader',
'./markdown-loader'
]
},
// {
// test: /.js$/,
// use: {
// loader: 'babel-loader', //处理es6代码当中的新特性
// options: {
// presets: ['@babel/preset-env'] //babel只是一个转换js代码的平台,在平台转换过程当中须要额外的插件
// }
// }
// }
]
},
//配置插件
plugins: [
//清理输出目录
//new CleanWebpackPlugin(),
//用于拷贝文件到输出目录 开发阶段最好不要使用这个插件 影响效率
// new CopyWebpackPlugin({
// patterns: [
// // 'public/**',
// 'public'
// ]
// }),
//自动生成index.html
// new HtmlWebpackPlugin({
// title: 'Webpack Plugin Sample',
// meta: {
// viewport: 'width=device-width'
// },
// filename: 'index.html'
// }),
//用于生成about.html
new HtmlWebpackPlugin({
filename: 'index.html'
}),
//自定义插件 删除生成的js文件当中的注释
new MyPlugin(),
//热更新插件
new webpack.HotModuleReplacementPlugin()
]
}
if (env === 'production') {
console.log('生成环境')
config.mode = 'production'
config.devtool = false
config.plugins = [...config.plugins, new CleanWebpackPlugin()]
} else {
console.log('开发环境')
}
return config
}
复制代码
// 开发环境
yarn webpack
// 生产环境
yarn webpack --env production
复制代码
//为代码注入全局成员
new webpack.DefinePlugin({
//符合JS语法的代码
API_BASE_URL: '"https://api.example.com"'
})
复制代码
Tree Shaking不是指某个配置选项,它是一组功能搭配使用后的效果
production模式下自动开启
其余模式开启
//集中配置webpack内部的一些优化功能
optimization: {
//在输出结果中只导出被外部使用了的成员
usedExports: true,
//开启代码压缩功能
minimize: true
}
复制代码
webpack将咱们全部的代码都打包到一块儿,若是咱们的应用程序很是复杂,模块很是多的状况下,那么咱们的打包结果就会特别的大,咱们的应用程序开始工做时并非每一个模块在启动时都是必要的,比较合理的方案是分包,按需加载,这样就能大大提升咱们应用程序的相应速度和运行效率
多入口打包存在一个小问题,不一样的打包入口当中必定会存在一些公用的部分
//把全部的公共模块提取到单独的bundle当中
splitChunks: {
chunks: 'all'
}
复制代码
部署前端资源文件时,会开启静态资源缓存,对于用户的浏览器而言,它就能够缓存咱们的静态资源文件,提升咱们总体应用程序的相应速度
生产模式下,文件名使用Hash,一旦资源文件发生改变,文件名称也会发生变化
hash:整个项目当中有任何一个地方发生改动,这一次打包过程中的hash值都会发生变化
chunkhash:在打包过程中只要是同一路的打包,chunkhash都是相同的
contenthash:根据输出文件的内容生成的hash值
能够经过占位符的方式指定生成hash的长度,例如:[contenthash:8]
env关键字可使用的环境,能够同时开启多个环境
browser
- 浏览器环境中的全局变量。node
- Node.js 全局变量和 Node.js 做用域。commonjs
- CommonJS 全局变量和 CommonJS 做用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。shared-node-browser
- Node.js 和 Browser 通用全局变量。es6
- 启用除了 modules 之外的全部 ECMAScript 6 特性(该选项会自动设置 ecmaVersion
解析器选项为 6)。worker
- Web Workers 全局变量。amd
- 将 require()
和 define()
定义为像 amd 同样的全局变量。mocha
- 添加全部的 Mocha 测试全局变量。jasmine
- 添加全部的 Jasmine 版本 1.3 和 2.0 的测试全局变量。jest
- Jest 全局变量。phantomjs
- PhantomJS 全局变量。protractor
- Protractor 全局变量。qunit
- QUnit 全局变量。jquery
- jQuery 全局变量。prototypejs
- Prototype.js 全局变量。shelljs
- ShellJS 全局变量。meteor
- Meteor 全局变量。mongo
- MongoDB 全局变量。applescript
- AppleScript 全局变量。nashorn
- Java 8 Nashorn 全局变量。serviceworker
- Service Worker 全局变量。atomtest
- Atom 测试全局变量。embertest
- Ember 测试全局变量。webextensions
- WebExtensions 全局变量。greasemonkey
- GreaseMonkey 全局变量。extends
parserOptions
ESLint 容许你指定你想要支持的 JavaScript 语言选项。默认状况下,ESLint 支持 ECMAScript 5 语法。你能够覆盖该设置,以启用对 ECMAScript 其它版本和 JSX 的支持。
ecmaVersion
- 默认设置为 3,5(默认), 你可使用 六、七、八、9 或 10 来指定你想要使用的 ECMAScript 版本。你也能够用使用年份命名的版本号指定为 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (same as 10)
sourceType
- 设置为 "script"
(默认) 或 "module"
(若是你的代码是 ECMAScript 模块)。
ecmaFeatures
复制代码
- 这是个对象,表示你想使用的额外的语言特性:
globalReturn
- 容许在全局做用域下使用 return
语句impliedStrict
- 启用全局 strict mode (若是 ecmaVersion
是 5 或更高)jsx
- 启用 JSXexperimentalObjectRestSpread
- 启用实验性的 object rest/spread properties 支持。(**重要:**这是一个实验性的功能,在将来可能会有明显改变。 建议你写的规则 不要 依赖该功能,除非当它发生改变时你愿意承担维护成本。)rules
globals