随着现代前端开发的复杂度和规模愈来愈庞大,已经不能抛开工程化来独立开发了,如react的jsx代码必须编译后才能在浏览器中使用;又如sass和less的代码浏览器也是不支持的。 而若是摒弃了这些开发框架,那么开发的效率将大幅降低。在众多前端工程化工具中,webpack
脱颖而出成为了当今最流行的前端构建工具。 然而大多数的使用者都只是单纯的会使用
,而并不知道其深层的原理。但愿经过如下的面试题总结能够帮助你们温故知新、查缺补漏,知其然而又知其因此然。css
三者都是前端构建工具,grunt和gulp在早期比较流行,如今webpack相对来讲比较主流,不过一些轻量化的任务仍是会用gulp来处理,好比单独打包CSS文件等。前端
grunt和gulp是基于任务和流(Task、Stream)的。相似jQuery,找到一个(或一类)文件,对其作一系列链式操做,更新流上的数据, 整条链式操做构成了一个任务,多个任务就构成了整个web的构建流程。vue
webpack是基于入口的。webpack会自动地递归解析入口所须要加载的全部资源文件,而后用不一样的Loader来处理不一样的文件,用Plugin来扩展webpack功能。react
因此总结一下:webpack
gulp和grunt须要开发者将整个前端构建过程拆分红多个`Task`,并合理控制全部`Task`的调用关系
webpack须要开发者找到入口,并须要清楚对于不一样的资源应该使用什么Loader作何种解析和加工复制代码
一样是基于入口的打包工具还有如下几个主流的:git
从应用场景上来看:github
因为parcel在打包过程当中给出的调试信息十分有限,因此一旦打包出错难以调试,因此不建议复杂的项目使用parcel
UglifyES
压缩ES6
代码不一样的做用web
loader
。 因此Loader的做用是让webpack拥有了加载和解析非JavaScript文件的能力。不一样的用法面试
module.rules
中配置,也就是说他做为模块的解析规则而存在。 类型为数组,每一项都是一个Object
,里面描述了对于什么类型的文件(test
),使用什么加载(loader
)和使用的参数(options
)plugins
中单独配置。 类型为数组,每一项是一个plugin
的实例,参数都经过构造函数传入。Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行如下流程:npm
在以上过程当中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,而且插件能够调用 Webpack 提供的 API 改变 Webpack 的运行结果。
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,而且每一个Loader经过链式操做,将源文件一步步翻译成想要的样子。
编写Loader时要遵循单一原则,每一个Loader只作一种"转义"工做。 每一个Loader的拿到的是源文件内容(source
),能够经过返回值的方式将处理后的内容输出,也能够调用this.callback()
方法,将内容返回给webpack。 还能够经过 this.async()
生成一个callback
函数,再用这个callback将处理后的内容输出出去。 此外webpack
还为开发者准备了开发loader的工具函数集——loader-utils
。
相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,Plugin 能够监听这些事件,在合适的时机经过 Webpack 提供的 API 改变输出结果。
webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。 这个机制能够作到不用刷新浏览器而将新变动的模块替换掉旧的模块。
原理:
首先要知道server端和client端都作了处理工做
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
UglifyJsPlugin
和ParallelUglifyPlugin
来压缩JS文件, 利用cssnano
(css-loader?minimize)来压缩cssoutput
参数和各loader的publicPath
参数来修改资源路径--optimize-minimize
来实现CommonsChunkPlugin
来提取公共代码externals
配置来提取经常使用库DllPlugin
和DllReferencePlugin
预编译资源模块 经过DllPlugin
来对那些咱们引用可是绝对不会修改的npm包来进行预编译,再经过DllReferencePlugin
将预编译的模块加载进来。Happypack
实现多线程加速编译webpack-uglify-parallel
来提高uglifyPlugin
的压缩速度。 原理上webpack-uglify-parallel
采用了多核并行压缩来提高压缩速度Tree-shaking
和Scope Hoisting
来剔除多余代码单页应用能够理解为webpack的标准模式,直接在entry
中指定单页应用的入口便可,这里再也不赘述
多页应用的话,可使用webpack的 AutoWebPlugin
来完成简单自动化的构建,可是前提是项目的目录结构必须遵照他预设的规范。 多页应用中要注意的是:
Npm
是目前最大的 JavaScript 模块仓库,里面有来自全世界开发者上传的可复用模块。你可能只是JS模块的使用者,可是有些状况你也会去选择上传本身开发的模块。 关于NPM模块上传的方法能够去官网上进行学习,这里只讲解如何利用webpack来构建。
NPM模块须要注意如下问题:
.css
文件也须要包含在发布的模块里。基于以上须要注意的问题,咱们能够对于webpack配置作如下扩展和优化:
output.libraryTarget='commonjs2'
使输出的代码符合CommonJS2 模块化规范,以供给其它模块导入使用babel-loader
把 ES6 代码转换成 ES5 的代码。再经过开启devtool: 'source-map'
输出SourceMap以发布调试。.babelrc
文件,为其加入transform-runtime
插件externals
配置项来告诉webpack哪些模块不须要打包。css-loader
和extract-text-webpack-plugin
来实现,配置以下:const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
module: {
rules: [
{
// 增长对 CSS 文件的支持
test: /\.css/,
// 提取出 Chunk 中的 CSS 代码到单独的文件中
use: ExtractTextPlugin.extract({
use: ['css-loader']
}),
},
]
},
plugins: [
new ExtractTextPlugin({
// 输出的 CSS 文件名称
filename: 'index.css',
}),
],
};
复制代码
Vue UI组件库的按需加载 为了快速开发前端项目,常常会引入现成的UI组件库如ElementUI、iView等,可是他们的体积和他们所提供的功能同样,是很庞大的。 而一般状况下,咱们仅仅须要少许的几个组件就足够了,可是咱们却将庞大的组件库打包到咱们的源码中,形成了没必要要的开销。
不过不少组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component
和AntDesign出品的babel-plugin-import
安装以上插件后,在.babelrc
配置中或babel-loader
的参数中进行设置,便可实现组件按需加载了。
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
复制代码
单页应用的按需加载 如今不少前端项目都是经过单页应用的方式开发的,可是随着业务的不断扩展,会面临一个严峻的问题——首次加载的代码量会愈来愈多,影响用户的体验。
经过import(*)
语句来控制加载时机,webpack内置了对于import(*)
的解析,会将import(*)
中引入的模块做为一个新的入口在生成一个chunk。 当代码执行到import(*)
语句时,会去加载Chunk对应生成的文件。import()
会返回一个Promise对象,因此为了让浏览器支持,须要事先注入Promise polyfill