作者: 文章来源:
本文原地址:https://www.mimiwuqi.com/webqianduan/196643.html
目录文章目录
现在的前端网页功能丰富,特别是 SPA(single page web application 单页应用)技术流行后,JavaScript 的复杂度增加和需要一大堆依赖包,还需要解决 Scss,Less……新增样式的扩展写法的编译工作。
所以现代化的前端已经完全依赖于 webpack 的辅助了。
现在最流行的三个前端框架,可以说和 webpack 已经紧密相连,框架官方都推出了和自身框架依赖的 webpack 构建工具。
react.js+WebPack
vue.js+WebPack
AngluarJS+WebPack
WebPack 可以看做是模块打包机:它做的事情是,分析你的项目结构,找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript 等),并将其转换和打包为合适的格式供浏览器使用。在 3.0 出现后,Webpack 还肩负起了优化项目的责任。
把一切都视为模块:不管是 css、JS、Image 还是 html 都可以互相引用,通过定义 entry.js,对所有依赖的文件进行跟踪,将各个模块通过 loader 和 plugins 处理,然后打包在一起。
按需加载:打包过程中 Webpack 通过 Code Splitting 功能将文件分为多个 chunks,还可以将重复的部分单独提取出来作为commonChunk,从而实现按需加载。把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载
Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。告诉 webpack 要使用哪个模块作为构建项目的起点,默认为./src/index.jsoutput:出口,告诉 webpack 在哪里输出它打包好的代码以及如何命名,默认为./distModule:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。Loader:模块转换器,用于把模块原内容按照需求转换成新内容。Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。三者都是前端构建工具,grunt 和 gulp 在早期比较流行,现在 webpack 相对来说比较主流,不过一些轻量化的任务还是会用 gulp 来处理,比如单独打包 CSS 文件等。
grunt 和 gulp 是基于任务和流(Task、Stream)的。
类似 jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据,整条链式操作构成了一个任务,多个任务就构成了整个 web 的构建流程。
webpack 是基于入口的。
webpack 会自动地递归解析入口所需要加载的所有资源文件,然后用不同的 Loader 来处理不同的文件,用 Plugin 来扩展 webpack 功能。
如果像以前开发时一个 html 文件可能会引用十几个 js 文件,而且顺序还不能乱,因为它们存在依赖关系,同时对于 ES6+等新的语法,less,sass 等 CSS 预处理都不能很好的解决……,此时就需要一个处理这些问题的工具。
多入口情况下,使用CommonsChunkPlugin来提取公共代码
通过externals配置来提取常用库
利用DllPlugin和DllReferencePlugin预编译资源模块通过DllPlugin来对那些我们
引用但是绝对不会修改的 npm 包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
使用Happypack实现多线程加速编译
使用webpack-uglify-paralle来提升uglifyPlugin的压缩速度。
原理上 webpack-uglify-parallel 采用了多核并行压缩来提升压缩速度
使用Tree-shaking和Scope Hoisting来剔除多余代码
Npm 是目前最大的 JavaScript 模块仓库,里面有来自全世界开发者上传的可复用模块。
你可能只是 JS 模块的使用者,但是有些情况你也会去选择上传自己开发的模块。
关于 NPM 模块上传的方法可以去官网上进行学习,这里只讲解如何利用 webpack 来构建。
NPM 模块需要注意以下问题:
代码层面:
研发流程层面:
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
单页应用可以理解为 webpack 的标准模式,直接在 entry 中指定单页应用的入口即可,这里不再赘述
多页应用的话,可以使用 webpack 的 AutoWebPlugin 来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。多页应用中要注意的是:
webpack 默认只能打包 js 文件,配置里的module.rules数组配置了一组规则,告诉 Webpack 在遇到哪些文件时使用哪些 Loader 去加载和转换打包成 js。
注意:
use属性的值需要是一个由 Loader 名称组成的数组,Loader 的执行顺序是由后到前的;
每一个 Loader 都可以通过 URL querystring的方式传入参数,例如 css-loader?minimize 中的 minimize 告诉 css-loader 要开启 CSS 压缩。
css-loader读取合并 CSS 文件
style-loader把 CSS 内容注入到 JavaScript 里
sass-loader解析 sass 文件(安装sass-loader,node-sass)
postcss-loader自动添加浏览器兼容前缀(postcss.config配置)
url-loader将文件转换为base64 URI。
vue-loader处理 vue 文件。
Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性。
Webpack 是通过 plugins 属性来配置需要使用的插件列表的。plugins 属性是一个数组,里面的每一项都是插件的一个实例,在实例化一个组件时可以通过构造函数传入这个组件支持的配置属性。
bundle:是由 webpack 打包出来的文件
chunk:是指 webpack 在进行模块依赖分析的时候,代码分割出来的代码块
module:是开发中的单个模块
HtmlWbpackPlugin自动在打包结束后生成 html 文件,并引入 bundle.js
cleanwebPackPlugin打包自动删除上次打包文件
ExtractTextPlugin插件的作用是提取出 JavaScript 代码里的 CSS 到一个单独的文件。
对此你可以通过插件的filename属性,告诉插件输出的 CSS 文件名称是通过[name]_[contenthash:8].css字符串模版生成的,里面的[name]代表文件名称,[contenthash:8]代表根据文件内容算出的 8 位 hash 值,还有很多配置选项可以在ExtractTextPlugin的主页上查到。
是一个映射关系,将打包后的文件隐射到源代码,用于定位报错位置
配置方式:
例如:devtool:‘source-map’
加不同前缀意义:
inline:不生成映射关系文件,打包进 main.jscheap:1.只精确到行,不精确到列,打包速度快 2.只管业务代码,不管第三方模块module:不仅管业务代码,而且管第三方代码eval:执行效率最快,性能最好最佳实践:
cheap-module-eval-source-mapcheap-mudole-source-map借助webpack.HotModuleReplacementPlugin(),devServer开启hot
场景 1:实现只刷新 css,不影响 js
场景 2:js 中实现热更新,只更新指定 js 模块
if (module.hot) {
module.hot.accept(’./library.js’, function() {
// Do something with the updated library module…
});
}
entry: {
home: resolve(__dirname, "src/home/index.js"),
about: resolve(__dirname, "src/about/index.js")
}
用于描述入口的对象。你可以使用如下属性:
dependOn:当前入口所依赖的入口。它们必须在该入口被加载前被加载。filename:指定要输出的文件名称。import:启动时需加载的模块。library:指定 library 选项,为当前 entry 构建一个 library。runtime:运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk。publicPath:当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。babel-polyfill的原理是当运行环境中并没有实现的一些方法,babel-polyfill会做兼容。
babel-runtime它是将 es6 编译成 es5 去执行。我们使用 es6 的语法来编写,最终会通过 babel-runtime 编译成 es5.也就是说,不管浏览器是否支持 ES6,只要是 ES6 的语法,它都会进行转码成 ES5.所以就有很多冗余的代码。
babel-polyfill它是通过向全局对象和内置对象的prototype上添加方法来实现的。比如运行环境中不支持Array.prototype.find方法,引入polyfill,我们就可以使用 es6 方法来编写了,但是缺点就是会造成全局空间污染。
babel-runtime:它不会污染全局对象和内置对象的原型,比如说我们需要Promise,我们只需要import Promise from'babel-runtime/core-js/promise即可,这样不仅避免污染全局对象,而且可以减少不必要的代码。
Stage 0 – 设想(Strawman):只是一个想法,可能有 Babel 插件。
Stage 1 – 建议(Proposal):这是值得跟进的。
Stage 2 – 草案(Draft):初始规范。
Stage 3 – 候选(Candidate):完成规范并在浏览器上初步实现。
Stage 4 – 完成(Finished):将添加到下一个年度版本发布中。
babel-preset-es2015:可以将 es6 的代码编译成 es5.
babel-preset-es2016:可以将 es7 的代码编译为 es6.
babel-preset-es2017:可以将 es8 的代码编译为 es7.
babel-preset-latest:支持现有所有 ECMAScript 版本的新特性
模块热更新是 webpack 的一个功能,它可以使得代码修改之后,不用刷新浏览器就可以更新。
在应用过程中替换添加删出模块,无需重新加载整个页面,是高级版的自动刷新浏览器。
优点:只更新变更内容,以节省宝贵的开发时间。调整样式更加快速,几乎相当于在浏览器中更改样式
借助import()语法异步引入组件,实现文件懒加载:prefetch,preloading
webpack 提倡多写异步代码,提升代码利用率,从而提升页面性能
先加载主业务文件,prefetch利用网络空闲时间,异步加载组件
import(/* webpackPrefetch: true / ‘LoginModal’);
preload和主业务文件一起加载,异步加载组件。
import(/ webpackPreload: true */ ‘ChartingLibrary’);
浏览器在用户访问页面的时候,为了加快加载速度,会对用户访问的静态资源进行存储,但是每一次代码升级或者更新,都需要浏览器去下载新的代码,最方便和最简单的更新方式就是引入新的文件名称。
在 webpack 中,可以在output给出输出的文件制定chunkhash,并且分离经常更新的代码和框架代码,通过 NameModulesPlugin 或者HashedModulesPlugin使再次打包文件名不变。
指打包中去除那些引入了但在代码中没用到的死代码。在 wepack 中 js treeshaking通过UglifyJsPlugin来进行,css 中通过 purify-CSS 来进行。
webpack-dev-server使用内存来存储 webpack 开发环境下的打包文件,并且可以使用模块热更新,比传统的 http 服务对开发更加有效。
mode/–mode参数,新增了mode/–mode参数来表示是开发还是生产(development/production)production侧重于打包后的文件大小,development侧重于goujiansud移除loaders,必须使用rules(在 3 版本的时候 loaders 和 rules 是共存的但是到 4 的时候只允许使用 rules)移除了CommonsChunkPlugin(提取公共代码),用optimization.splitChunks和optimization.runtimeChunk来代替支持 es6 的方式导入 JSON 文件,并且可以过滤无用的代码。
相关阅读推荐:Webpack 常见面试题总结(二)
更多 建站教程 请访问 https://www.mimiwuqi.com/webqianduan/