webpack是一个用于现代的Javascript应用程序,一个模块打包工具,当webpack处理应用程序时,会从内部一个或多个入口点构建一个依赖图,然后将项目中需要的每一个模块合成一个或多个bundles
webpack也可以做一个兼容性处理,对于浏览器或低版本的浏览器不认识的代码转换为可以被执行的
一些核心概念
- 入口(entry - input)
作为一个项目打包的入口,可以配置一个或多个入口
- 出口(output)
打包后的应用输出,一个或者多个
- loader
loader用于源代码的转化, 比如浏览器不认识less,可以加入less-loader处理less文件转为css
- plugin
插件用于webpack的整个生命周期,可以对构建程序和输出应用加点料
- env
分为生产环境和开发环境,二者有相同、和不同之处
- 浏览器兼容性
转换为低版本浏览器的代码
一些术语
- vendor
一些不经常更新但又被多个模块依赖的包
- mainifest
用于管理打包后各个模块之间的依赖映射
- runtime
在运行时,webpack会将打包后的文件假如一些运行时文件,这个文件用于管理各个模块之间的依赖连接程序所需要的代码,包含模块交互时,连接模块所需的加载和解析逻辑,其中包括已经加载的和为加载或者延迟加载的逻辑
Setup
在一个项目的根目录执行的npm start
, 这个命令时npm内置的一个script。可以在本项目中执行一段脚本,比如启动一个项目的开发服务器,这种情况称为开发时
开发时webpack需要做的工作, 也就三样 HTML、Javascript、CSS。
对于HTML我们可以采用html-webpack-plugin, 这是一个插件,可以帮助webpack自动把打包好的js文件插入到页面dom节点中,在本地或者内存中。
对于css的处理,采用css-loader, less-loader, style-loader
,less-loader负责将less文件转为css, css-loader会对import或者url进行处理,style-loader可以把处理完成的css内容,创建一个style
标签插入到文档中. css-minimizer-webpack-plugin也可以用于对css 的处理,它的作用是把css文件单独抽离成一个文件,不过一般用于构建时,在开发时使用style-loader更方便。
对于js,会有babel-loader,把一些高级语法转为低版本浏览器可以识别的代码,但是通常情况下不会单独来写js。 比如babel-preset-react一个babel的预设, 可以把jsx语法转换为createElement()
或者项目中使用ts,会有ts-loader 用于将ts文件转为js文件
或者其他静态资源,比如开发时会使用到.svg, .json, .png, .jpg
对于这种静态资源来说会有file-loader、url-loader 等进行处理
使用loaders的方法:
const webpackConf = {
module: {
// 增加loader
//! loader的
rules: []
}
};
在开发时我们希望开发时越简单越方便越好,比如我们在引入模块时,不想多敲两个后缀名这个使用可以使用resolve
的配置, 当然对于这个选项应该把常用的文件尽量靠前写
const webpackConf = {
resolve: {
extensions: ['.js', '.json', '.ts'],
}
};
在或者常常在项目中会使用@符号或者$符号,来使用相对于根目录的绝对路径, 这个配置由resolve.alias{}
来决定的
开发时一般会使用html的插件,用于开发时
const webpackConf = {
plugins: [
new HTMLWebpackPlugins({
title: "webpackApp"
})
]
};
开发时需要的服务器,webpack也有提供,就是wbpack-dev-server , 这个一个单独的包,但是一般会和webpack一起使用
const webpackConf = {
devServer: {
port: 8090, // 设置端口,默认为3000,
static: {}, // 用于开发时静态资源的服务器
proxy:{}, // 用于在前端遇到跨域时用到的配置
}
};
默认情况wbepack的监视到文件的变化时reload更新,这种选择在项目规模小的时候不会有感觉,但是规模打的时候,一个realode时间也需要点, 通过热模块替换可以局部刷新,去解决这个问题
也就是webpackConf.devServer.hot = true
开启热模块替换,同时使用增加webpack内置的插件HotModuleReplacementPlugin
a, 或者在代码中自己配置。 目前版本[webpack:5.64.4] 没有热替换功能,源文件改变时页面还是reload更新
在一些第三方库源代码中经常会看到DEV、NODE_VEN、__DEV__
这种全局的变量,用来区分是不是开发环境,这种变量是由插件webpack.DefinePlugin
干的事
比如在浏览器中使用DEV变量
// webpackConf
[
new webpack.DefinePlugin({
DEV: true
})
]
// .js
console.log(DEV); === true
但是这种一般编辑器或者ts,eslint会报错,所以需要手动注册全局变量。 define-plugin 插件的推荐使用使用string,也就是JSON.stringify(value)
一般在开发环境在调试代码时首先会在控制台看见报错信息,或者函数的调用栈用于排查错误,这个功能在webpack里面就是soucemap干的事,也就是把打包后的代码和本地形成映射关系,报错以后可以查看详细的报错信息
在开发时我们会依赖第三方模块,比如lodash, rxjs, react
这些库不管是开发还是构建时,我们的项目都会依赖,但是假如没有处理,每次打包、或者dev环境重新启动时都会重新处理这些文件,所以这个时候需要把第三方库拆分出来, 这会用到code-splittin 对第三方库或者依赖次数多而不经常变化的文件进行拆分,单独打包,或者在线上环境使用CDN
对于拆分后,webpack如何知道当前的文件有没有拆分呢,这就是缓存的其中一个作用, 缓存可以对不长修改的文件作处理,在下一次变动时会重新生成缓存,假如存在直接使用缓存中的数据。
wbepack5以后把缓存单独抽了一个选项就是Cache, cache不仅可以用于webpack打包的文件,还可以用于浏览器缓存中,也就是HTTP缓存
在项目开发完毕,准备上线时,代码中可能存在一些未使用的变量,或者函数,变量可以通过ts来解决,但是模块化,ts解决不了,这时对打包的代码需要增加tree-shaking 处理,也就是整个项目中把没有使用的代码块剔除掉
剔除掉以后的代码会进行压缩拆分等操作,对于html的压缩HTML插件本身就支持,css的压缩采用mini-css插件,js的压缩webpack已经内置了压缩工具,只需要指定为生产环境即可
一个项目的代码完成以后,会很庞大,那么这个庞大的文件在加载到页面以后一定会阻止页面渲染,尽管存在defer,async
这样的选项。 这时可以使用optimization 缩减的选项, 可以更细粒度的拆分chunk。 比如把node_moduels 中拆一个,src拆一个或多个,一个chunk超过指定大小以后开始拆分等等…