webpack是一个性能最好的模块化工具
现在node那么好,前端想引用已经写好的node包加速开发,问题是如何在浏览器中引入nodeJS文件?并且是大量的。 浏览器引入JS文件有两种方式,在标签中直接嵌入JS代码或者src引入一个js文件,这会导致两个重要的问题,一个是作用域的问题,JS加载的太多,变量一旦重名,程序会产生错误。作用域的问题,后来使用IFEE去解决,封闭作用域,再把想要暴露的暴露出来,然后使用工具将IFEE连接起来,比如grunt, gulp, broccoli, nginx。这样就解决了作用域的问题。另外一个是性能问题,第一,浏览器并发下载是有数量限制的,哪怕是使用最快的http2.0协议,也是依然有性能瓶颈的。第二,每一次修改一个文件,都需要整体重新构建,重新连接这些文件,第三,用了2K的代码却要引入一个2M的库?
这时模块化的概念应运而生,CMD,AMD,UMD,混用才解决了第三,还不支持浏览器。后来产生了一些解决方Browserify(static),Requirejs(loader),SystemJS(loader),支持了浏览器,但是是全部加载/同步加载/没有静态分析,加载起来,数量多,体积大,性能不好。(出现懒加载,相当于一个异步加载。但只是稍微提升了速度)
后来出来的ESM,终于实现模块化,真正解决了第二第三,又可以重用又可以按需自动引入,支持浏览器,但是在浏览器中非常慢,本来JavaScript的解释性就比编译语言慢了,如果在执行任务中还要分析依赖,那就更慢了?
性能,性能,还是性能?性能一般从两方面去考虑,响应时间和吞吐率。 我们需要一个怎样的工具?首先不可以动态引入,那么需要提前做好静态分析,提高响应时间。webpack将所有资源构建成一棵树,在同一时间引入,这在一定程度从本质上解决了动态引入的性能问题。
再者,数量和体积上需要控制,进行按需引入,用到的模块被引入,没用到的先不引入,提高吞吐率。webpack可以按需加载,对于凡是运行了的,实际用到了的,才会被webpack处理和打包,从而减少了文件的数量和大小。本质上依赖于treeshaking机制。
并且有没有一个构想?所有的静态资源都可以做一个分析,做一个引入的管理?提高效率。webpack有一个概念,一切皆模块,把任何其他语言,其他形式的东西都转换为浏览器可识别的东西,都转换成JS可以操作的东西
另外webpack还会做一些其他的处理和优化,使得开发更加能够适应不同的场景,适应不同的应用,以适应今天前端的开发要求。这么好用,那我们赶紧开始吧。
你需要认识webpack的几个主要的部分
按照前面所说,webpack进行一个转换,所以下面webpack所具有的的几个部分就比较好理解了
- entry 你以为这里写你想要转化的各个文件,webpack有更好的方法,你只需要给它一个起始的位置,它自己会进行引入和构建
- output 这里是告诉webpack做完处理和打包以后,你想存放在哪里,需要指定filename和path
- mode 这里是告诉webpack是处在生产模式production 还是开发模式 development ,模式不同,webpack提供给你的服务不同,简直就是五星级服务
- module 这里指定什么东西用什么去转换,还记得我们的关键词么,转换。各种loader 可以将各种类型的文件转换为 webpack 能够处理的模块。loader里面有两个属性,test是找什么样的文件,use是使用哪种loader进行转换。
- plugins 这里是其他需要使用的插件,都是写好的,拿来主义。想要使用一个插件,需要先require,添加到plugin数组中,再使用new操作符创建一个它的实例
开发中,你会遇到各种问题
你以为万事大吉了?其实在开发中你会遇到各种各样的问题,不用担心,webpack能够帮助你解决大多数,我们就来讲一讲,牛X走起!新司机上路,小心驾驶。不遇问题的司机不是好司机???
-
应用程序,第三方库,多页面应用程序,它们主要的前端js功能不同,那么如何创建一个多入口的构建工程?
const config = { entry: { app: './src/app.js', vendors: './src/vendors.js' } }; const config = { entry: { pageOne: './src/pageOne/index.js', pageTwo: './src/pageTwo/index.js', pageThree: './src/pageThree/index.js' } };
多个入口,会有多个js资源,webpack生成好的js资源注入到模板,生成不同的HTML文件。
- 多入口但是只有一个输出配置,应该怎么操作?使得html只引用自己所需要部分的js/css资源,不会造成冗余代码,使得页面加载时间过长?
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
多入口会创建多个chunk,要是能把不同的chunk配置给不同的html就好了。
- 是否有现成的插件可以实现指定的注入?查到HtmlWebpackPlugin
new HtmlWebpackPlugin({
filename: 'xxx.html',
chunks:['xxxx'],
template: path.resolve(__dirname , 'xxxxx.html')
})
这段只看过文档,只是一个推理/设想,没有打过代码验证过。
- 下面要说说别的东西了,跟上面没有关系。mode。看看文档里都提供了哪些?
module.exports = {
+ mode: 'development'
- plugins: [
- new webpack.NamedModulesPlugin() 给每个模块命名
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }), 给每个chunks命名,可以自定义
- ]
}
module.exports = {
+ mode: 'production',
- plugins: [
- new UglifyJsPlugin(/* ... */), 混淆&压缩JS
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }), 允许创建一个在编译时可以配置的全局常量
- new webpack.optimize.ModuleConcatenationPlugin(), 作用域提升,加快速度
- new webpack.NoEmitOnErrorsPlugin() 防止程序报错,就算有错误也给我继续编译
- ]
}
这些插件在遇到问题的时候,可以再具体看怎么使用
- 下面说loader。loader有如下特性:
- loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
- loader 可以是同步的,也可以是异步的。
- loader 运行在 Node.js 中,并且能够执行任何可能的操作。
- loader 接收查询参数。用于对 loader 传递配置。
- loader 也能够使用 options 对象进行配置。
- 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
- 插件(plugin)可以为 loader 带来更多特性。
- loader 能够产生额外的任意文件。
- plugins插件目的在于解决 loader 无法实现的其他事。 webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, compilation => {
console.log("webpack 构建过程开始!");
});
}
}
文档里面有一句—————webpack 插件机制是整个 webpack 工具的骨架,而 webpack 本身也是利用这套插件机制构建出来的。那么webpack的插件机制是怎么样的呢? 从如何创建一个webpack插件,我们来看看能不能找到一点线索。一个 Webpack 的插件其实包含以下几个条件:
- 一个 js 命名函数。
- 在原型链上存在一个 apply 方法。
- 为该插件指定一个 Webpack 的事件钩子函数。(tip:钩子函数是事件开始时的函数,可以当做是一个监听,回调函数事件结束时的函数)
- 使用 Webpack 内部的实例对象(Compiler 或者 Compilation)具有的属性或者方法。
- 当功能完成以后,需要执行 Webpack 的回调函数。
一个推测是:webpack的核心可能就是Compiler 或者 Compilation对象,应该还有事件流,通过钩子函数监听,被执行过的一个个Compiler 或者 Compilation对象,才会被打包在bundle文件中。
- 另一个话题————模块modules 把程序分解模块,这比程序更小,更容易校验、调试和测试。webpack支持的模块类型有 ES2015 import 语句, CommonJS require() 语句, AMD define 和 require 语句, css/sass/less 文件中的 @import 语句, 样式(url(...))或 HTML 文件中的图片链接(image url), coffeescript, typescript, babel, sass, less, stylus. 模块解析——————resolver 是一个库(library),用于帮助找到模块的绝对路径。 使用 enhanced-resolve,webpack 能够解析三种文件路径:绝对路径,相对路径,模块路径
每个文件系统访问都被缓存,以便更快触发对同一文件的多个并行或串行请求。在观察模式下,只有修改过的文件会从缓存中摘出。如果关闭观察模式,在每次编译前清理缓存。