-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Webpack #57
Comments
有哪些常见的Loader,你用过哪些首先我们要知道webpack默认只会处理JS之间的依赖关系。 但是webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。根据这个原因,所以我们可以很直接地推断,对于不同类型的文件一定有相应的loader,事实上也是如此,存在file-loader、image-loader、json-loader、style-loader、sass-loader、css-loader、postcss-loader等。 你也可以使用 Node.js 来很简单地编写自己的 loader。
用过file-loader, url-loader, ts-loader, bable-loader, less-loader,postcss-loader, css-loader, style-loader 其中,style-loader和css-loade的区别是什么呢? 由于每个loader的功能都是单一的,各自拆分独立。而webpack默认只能处理js模块间的依赖关系。 所以css-loader主要负责就是css模块间的依赖关系以及js对css的引用,它能够处理@import和url语句,处理css-modules,并将结果作为一个js模块返回。 css-loader返回的不是css样式代码的文本,而是一个js模块的代码。 那么这时就需要style-loader来将这些js代码形式的样式来整合到style标签中让他们生效。 有哪些常见的Plugin,你用过哪些
用过define-plugin、html-webpack-plugin,mini-css-extract-plugin,IgnorePlugin Loader 和Plugin 的区别Loader本质上就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。 Plugin本质上是一个插件,基于Tapable事件流,通过访问compiler和compilation上的hooks来监听构建流程中的生命周期,达到在特定时机执行自己想做的事情来干预构建结果。 Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。 Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。 是否写过Loader?简单描述一下编写loader的思路?
是否写过Plugin?简单描述一下编写Plugin的思路?webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在特定的阶段钩入想要添加的自定义功能。Webpack 的 Tapable 事件流机制保证了插件的有序性,使得整个系统扩展性良好。
|
webpack 构建流程
线上环境怎么使用 source mapsource map 是将编译、打包、压缩后的代码映射回源代码的过程。打包压缩后的代码不具备良好的可读性,想要调试源码就需要 soucre map。 hidden-source-map:借助第三方错误监控平台 Sentry 使用 注意:避免在生产中使用 inline- 和 eval-,因为它们会增加 bundle 体积大小,并降低整体性能。 |
文件监听原理在发现源码发生变化时,自动重新构建出新的输出文件。
**缺点:**每次需要手动刷新浏览器 **原理:**轮询判断文件的最后编辑时间是否变化,如果某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等 aggregateTimeout 后再执行构建。 |
Webpack 热更新热更新的表现是基于 如何开启热更新HMR是Webpack内置的功能,通过 热更新原理每一次构建后控制台都会输出三个信息 新的Hash值:a61bdd6e82294ed06fa3 首先,我们知道Hash值代表每一次编译的标识。其次,根据新生成文件名可以发现,上次输出的Hash值会作为本次编译新生成的文件标识。依次类推,本次输出的Hash值会被作为下次热更新的标识。 具体流程如下:
参考: |
如何对bundle体积进行监控和分析?VSCode 中有一个插件 bundlesize 工具包可以进行自动化资源体积监控。 |
文件指纹是什么?怎么用?文件指纹是每次打包完成后文件名的后缀。 hash和chunkhash通常被用来作为文件指纹。
JS的文件指纹设置设置 output 的 filename,用 chunkhash。 因为js内容最终会被合并打包成一个或者躲过chunk,所以当文件内容发生改变时,只有对应的chunk的内容会随之改变,所以需要使用chunkhash。 CSS的文件指纹设置设置 MiniCssExtractPlugin 的 filename,使用 contenthash。 Webpack把所有类型的文件都以js为汇聚点打成一个bundle,改了css也会导致整个js的hash发生改变,所以最好通过MiniCssExtractPlugin 把css独立抽取出来,所以使用contenthash。 图片的文件指纹设置设置file-loader的name,使用hash。 图片资源的名称是否需要变更取决于自身的内容是否发生改变,所以使用文件内容的hash, 占位符名称及含义: ext 资源后缀名 总结总的来说,文件指纹是用来为静态资源更新做增量更新的,目的是在资源发生变更的时候,能够通过文件名来区分版本,避免文件内容已经变更,但是由于浏览器缓存导致页面没有变化。 由于由于js会被打包成不同的chunk,所以对于js应该使用chunkhash,而CSS通过MiniCssExtractPlugin抽离后,在css发生变更时并不会使chunkhash发生变更,所以可以使用contenthash,css和js隔离也可以避免不必要的更新。图片资源则使用file-loader处理,使用文件内容的hash |
如何优化webpack的构建速度1、使用高版本的 Webpack 和 Node.js
webpack-paralle-uglify-plugin
3、图片压缩
4、缩小打包作用域
5、提取页面公共资源
6、DLLPlugin分包 7、HashedModuleIdsPlugin 8、充分利用缓存提升二次构建速度
9、Tree shaking 打包过程中检测工程中没有引用过的模块并进行标记,在资源压缩时将它们从最终的bundle中去掉(只能对ES6 Modlue生效) 开发中尽可能使用ES6 Module的模块,提高tree shaking效率 禁用 babel-loader 的模块依赖解析,否则 Webpack 接收到的就都是转换过的 CommonJS 形式的模块,无法进行 tree-shaking 使用 PurifyCSS(不在维护) 或者 uncss 去除无用 CSS 代码 purgecss-webpack-plugin 和 mini-css-extract-plugin配合使用(建议) |
bable的原理大多数JavaScript Parser遵循 estree 规范,Babel 最初基于 Babel大概分为三大部分: 1、解析:将代码转换成 AST
2、转换:访问 AST 的节点进行变换操作生产新的 AST Taro就是利用 babel 完成的小程序语法转换 |
webpack 是什么?
webpack 是一个现代 JavaScript 应用程序的静态模块打包器,当 webpack 处理应用程序时,会递归构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将这些模块打包成一个或多个 bundle。
👆🏻上面是官网上的说明,具体到应用场景中,webpack有如下的作用:
webpack 的核心概念
模块打包运行原理
如果面试官问你Webpack是如何把这些模块合并到一起,并且保证其正常工作的,你是否了解呢?
首先我们应该简单了解一下webpack的整个打包流程:
1、读取webpack的配置参数(从[email protected]版本开始,就可以不需要配置文件了,有默认配置项);
2、启动webpack,创建Compiler对象并开始解析项目;
3、从**入口文件(entry)**开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树;
4、对不同文件类型的依赖模块文件使用对应的Loader进行编译,最终转为Javascript文件;
5、整个过程中webpack会通过发布订阅模式,向外抛出一些hooks,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。
其中文件的解析与构建是一个比较复杂的过程,在webpack源码中主要依赖于compiler和compilation两个核心对象实现。
而每个模块间的依赖关系,则依赖于AST语法树。每个模块文件在通过Loader解析完成之后,会通过acorn库生成模块代码的AST语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。
最终Webpack打包出来的bundle文件是一个IIFE的执行函数(立即执行函数)。
**立即执行函数:**一个匿名的立即执行的函数,由于其匿名函数的关系,在其执行后会立即被释放,所以不会污染全局对象。
和webpack4相比,webpack5打包出来的bundle做了相当的精简。在上面的打包demo中,整个立即执行函数里边只有三个变量和一个函数方法,
__webpack_modules__
存放了编译后的各个文件模块的JS内容,__webpack_module_cache__
用来做模块缓存,__webpack_require__
是Webpack内部实现的一套依赖引入函数。最后一句则是代码运行的起点,从入口文件开始,启动整个项目。其中值得一提的是
__webpack_require__
模块引入函数,我们在模块化开发的时候,通常会使用ES Module或者CommonJS规范导出/引入依赖模块,webpack打包编译的时候,会统一替换成自己的__webpack_require__
来实现模块的引入和导出,从而实现模块缓存机制,以及抹平不同模块规范之间的一些差异性。你知道sourceMap是什么吗?
sourceMap是一项将编译、打包、压缩后的代码映射回源代码的技术,由于打包压缩后的代码并没有阅读性可言,一旦在开发中报错或者遇到问题,直接在混淆代码中debug问题会带来非常糟糕的体验,sourceMap可以帮助我们快速定位到源代码的位置,提高我们的开发效率。sourceMap其实并不是Webpack特有的功能,而是Webpack支持sourceMap,像JQuery也支持souceMap。
既然是一种源码的映射,那必然就需要有一份映射的文件,来标记混淆代码里对应的源码的位置,通常这份映射文件以.map结尾,里边的数据结构大概长这样:
是否写过Loader?简单描述一下编写loader的思路?
loader其实是一个函数,接收一段js代码字符串或者buffer,进行操作后再将js代码字符串输出给到下一个loader
是否写过Plugin?简单描述一下编写plugin的思路?
如果说Loader负责文件转换,那么Plugin便是负责功能扩展。Loader和Plugin作为Webpack的两个重要组成部分,承担着两部分不同的职责。
上文已经说过,webpack基于发布订阅模式,在运行的生命周期中会广播出许多事件,插件通过监听这些事件,就可以在特定的阶段执行自己的插件任务,从而实现自己想要的功能。
既然基于发布订阅模式,那么知道Webpack到底提供了哪些事件钩子供插件开发者使用是非常重要的,上文提到过compiler和compilation是Webpack两个非常核心的对象,其中compiler暴露了和 Webpack整个生命周期相关的钩子(compiler-hooks),而compilation则暴露了与模块和依赖有关的粒度更小的事件钩子(Compilation Hooks)。
Plugin的开发和开发Loader一样,需要遵循一些开发上的规范和原则:
The text was updated successfully, but these errors were encountered: