谈谈webpack?
webpack是一个模块打包工具,可使用它管理项目中的模块依赖,并编译输出模块所需的静态文件。它能够很好地管理、打包开发中所用到的HTML,CSS,JavaScript和静态文件(图片,字体)等,让开发更高效。对于不一样类型的依赖,webpack有对应的模块加载器,并且会分析模块间的依赖关系,最后合并生成优化的静态资源。css
webpack的基本功能和工做原理?
代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等
代码分割:提取多个页面的公共代码、提取首屏不须要执行部分的代码让其异步加载
模块合并:在采用模块化的项目有不少模块和文件,须要构建功能把模块分类合并成一个文件
自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
代码校验:在代码被提交到仓库前须要检测代码是否符合规范,以及单元测试是否经过
自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。html
webpack构建过程:
entry里配置的module开始递归解析entry依赖的全部module, 每找到一个module,就会根据配置的loader去找对应的转换规则。前端
对module进行转换后,再解析出当前module依赖的module 这些模块会以entry为单位分组,一个entry和其全部依赖的module被分到一个组Chunk。webpack
最后webpack会把全部Chunk转换成文件输出 在整个流程中webpack会在恰当的时机执行plugin里定义的逻辑web
webpack打包原理:
将全部依赖打包成一个bundle.js,经过代码分割成单元片断按需加载。npm
什么是entry,output?
entry 入口,告诉webpack要使用哪一个模块做为构建项目的起点,默认为./src/index.js
output 出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为./distjson
什么是bundle,chunk,module?
- bundle是webpack打包出来的文件
- chunk是webpack在进行模块的依赖分析的时候,代码分割出来的代码块
- module是开发中的单个模块
npm打包时须要注意哪些?如何利用webpack来更好的构建?
哪些常见的Loader?他们是解决什么问题的?
file-loader:把文件输出到一个文件夹中,在代码中经过相对 URL 去引用输出的文件;gulp
url-loader:和 file-loader 相似,可是能在文件很小的状况下以 base64 的方式把文件内容注入到代码中去;后端
source-map-loader:加载额外的 Source Map 文件,以方便断点调试;数组
image-loader:加载而且压缩图片文件;
babel-loader:把 ES6 转换成 ES5;
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性;
style-loader:把 CSS 代码注入到 JavaScript 中,经过 DOM 操做去加载 CSS;
eslint-loader:经过 ESLint 检查 JavaScript 代码;
webpack规范
webpack默认遵循commonjs规范 module.exports
使用webpack进行打包时有两种模式:
- 模式:主要是用于测试,代码调试等;
- 模式:要考虑性能问题,要压缩 若是没有插件 就不会压缩;
默认状况下webpack的配置文件叫webpack.config.js,能够经过--config指定webpack的配置文件名
loader
css须要两个loader来处理:css-loader style-loader
postcss-loader 他提供了一种方式用 JavaScript 代码来处理 CSS。它负责把 CSS 代码解析成抽象语法树结构(Abstract Syntax Tree,AST),再交由插件来进行处理。
-webkit-transform: rotate(45deg); transform: rotate(45deg);
mini-css-extract-plugin 之前都是之间引入内部样式,把css专门打包成一个css文件,在index.html文件中引入css
optimize-css-assets-webpack-plugin css压缩
terser-webpack-plugin css压缩 js不能压缩了,而后有一个插件,能压缩js
file-loader 是让webpack打包图片
url-loader可让图片转化base64,也可让webpack打包图片
webpack 默认状况下不支持js的高级语法,因此须要使用babel;
babel转化; npm i @babel/core @babel/preset-env babel-loader --save-dev
plugins:
html-webpack-plugin 根据模块生成一个html文件 此时不会在dist文件夹下面新建index文件了
我须要在public新建 index文件
根据这个模板文件 在内存中生成 index.html 而后自动引入bundle.js
clean-webpack-plugin 去掉没有用到的模块
webpack与grunt、gulp的不一样?
三者都是前端构建工具,grunt和gulp在早期比较流行,如今webpack相对来讲比较主流,不过一些轻量化的任务仍是会用gulp来处理,好比单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。相似jQuery,找到一个(或一类)文件,对其作一系列链式操做,更新流上的数据, 整条链式操做构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所须要加载的全部资源文件,而后用不一样的Loader来处理不一样的文件,用Plugin来扩展webpack功能。
总结一下:
gulp和grunt须要开发者将整个前端构建过程拆分红多个`Task`,并合理控制全部`Task`的调用关系 webpack须要开发者找到入口,并须要清楚对于不一样的资源应该使用什么Loader作何种解析和加工
gulp更像后端开发者的思路,须要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
有哪些常见的Plugin?他们是解决什么问题的?
- define-plugin:定义环境变量
- commons-chunk-plugin:提取公共代码
- uglifyjs-webpack-plugin:经过UglifyES压缩ES6代码
什么是loader,plugins,区别?
不一样的做用
- Loader Webpack将一切文件视为模块,可是webpack原生是只能解析js文件,若是想将其余文件也打包的话,就会用到loader。 因此Loader的做用是让webpack拥有了加载和解析非JavaScript文件的能力。
- Plugin Plugin能够扩展webpack的功能,让webpack具备更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 能够监听这些事件,在合适的时机经过 Webpack 提供的 API 改变输出结果。
不一样的用法
- Loader在module.rules中配置,也就是说他做为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
- Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都经过构造函数传入。
webpack的构建流程是什么?从读取配置到输出文件这个过程?
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行如下流程:
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步获得的参数初始化 Compiler 对象,加载全部配置的插件,执行对象的 run 方法开始执行编译;
- 肯定入口:根据配置中的 entry 找出全部的入口文件;
- 编译模块:从入口文件出发,调用全部配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到全部入口依赖的文件都通过了本步骤的处理;
- 完成模块编译:在通过第4步使用 Loader 翻译完全部模块后,获得了每一个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每一个 Chunk 转换成一个单独的文件加入到输出列表,这步是能够修改输出内容的最后机会;
- 输出完成:在肯定好输出内容后,根据配置肯定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程当中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,而且插件能够调用 Webpack 提供的 API 改变 Webpack 的运行结果。
是否写过Loader和Plugin?描述一下编写loader或plugin的思路?
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,而且每一个Loader经过链式操做,将源文件一步步翻译成想要的样子。
编写Loader时要遵循单一原则,每一个Loader只作一种"转义"工做。 每一个Loader的拿到的是源文件内容(source),能够经过返回值的方式将处理后的内容输出,也能够调用this.callback()方法,将内容返回给webpack。 还能够经过 this.async()生成一个callback函数,再用这个callback将处理后的内容输出出去。 此外webpack还为开发者准备了开发loader的工具函数集——loader-utils。
相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,Plugin 能够监听这些事件,在合适的时机经过 Webpack 提供的 API 改变输出结果。
webpack的热更新是如何作到的?说明其原理?
webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。 这个机制能够作到不用刷新浏览器而将新变动的模块替换掉旧的模块。
原理:

首先要知道server端和client端都作了处理工做
- 第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块从新编译打包,并将打包后的代码经过简单的 JavaScript 对象保存在内存中。
- 第二步是 webpack-dev-server 和 webpack 之间的接口交互,而在这一步,主要是 dev-server 的中间件 webpack-dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API对代码变化进行监控,而且告诉 webpack,将代码打包到内存中。
- 第三步是 webpack-dev-server 对文件变化的一个监控,这一步不一样于第一步,并非监控代码变化从新打包。当咱们在配置文件中配置了devServer.watchContentBase 为 true 的时候,Server 会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload。注意,这儿是浏览器刷新,和 HMR 是两个概念。
- 第四步也是 webpack-dev-server 代码的工做,该步骤主要是经过 sockjs(webpack-dev-server 的依赖)在浏览器端和服务端之间创建一个 websocket 长链接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据这些 socket 消息进行不一样的操做。固然服务端传递的最主要信息仍是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
- webpack-dev-server/client 端并不可以请求更新的代码,也不会执行热更模块操做,而把这些工做又交回给了 webpack,webpack/hot/dev-server 的工做就是根据 webpack-dev-server/client 传给它的信息以及 dev-server 的配置决定是刷新浏览器呢仍是进行模块热更新。固然若是仅仅是刷新浏览器,也就没有后面那些步骤了。
- HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的 hash 值,它经过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个 json,该 json 包含了全部要更新的模块的 hash 值,获取到更新列表后,该模块再次经过 jsonp 请求,获取到最新的模块代码。这就是上图中 七、八、9 步骤。
- 而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
- 最后一步,当 HMR 失败后,回退到 live reload 操做,也就是进行浏览器刷新来获取最新打包代码。
webpack来优化前端性能?(提升性能和体验)
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
- 代码。删除多余的代码、注释、简化代码的写法等等方式。能够利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
- CDN加速。在构建过程当中,将引用的静态资源路径修改成CDN上对应的路径。能够利用webpack对于output参数和各loader的publicPath参数来修改资源路径
- 死代码(Tree Shaking)。将代码中永远不会走到的片断删除掉。能够经过在启动webpack时追加参数--optimize-minimize来实现
- 公共代码。
如何提升webpack的构建速度?
- 多入口状况下,使用CommonsChunkPlugin来提取公共代码
- 经过externals配置来提取经常使用库
- 利用DllPlugin和DllReferencePlugin预编译资源模块 经过DllPlugin来对那些咱们引用可是绝对不会修改的npm包来进行预编译,再经过DllReferencePlugin将预编译的模块加载进来。
- 使用Happypack 实现多线程加速编译
- 使用webpack-uglify-parallel来提高uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提高压缩速度
- 使用Tree-shaking和Scope Hoisting来剔除多余代码
怎么配置单页应用?怎么配置多页应用?
单页应用能够理解为webpack的标准模式,直接在entry中指定单页应用的入口便可,这里再也不赘述
多页应用的话,可使用webpack的 AutoWebPlugin来完成简单自动化的构建,可是前提是项目的目录结构必须遵照他预设的规范。 多页应用中要注意的是:
- 每一个页面都有公共的代码,能够将这些代码抽离出来,避免重复的加载。好比,每一个页面都引用了同一套css样式表
- 随着业务的不断扩展,页面可能会不断的追加,因此必定要让入口的配置足够灵活,避免每次添加新页面还须要修改构建配置