webpack 的构建流程是什么
- 初始化参数:解析webpack配置参数,合并shell传入和webpack.config.js文件配置的参数,形成最后的配置结果;
- 开始编译:上一步得到的参数初始化compiler对象,注册所有配置的插件,插件监听webpack构建生命周期的事件节点,做出相应的反应,执行对象的run方法开始执行编译;
- 确定入口:从配置的entry入口,开始解析文件构建AST语法树,找出依赖,递归下去;
- 编译模块:递归中根据文件类型和loader配置,调用所有配置的loader对文件进行转换,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译并输出:递归完事后,得到每个文件结果,包含每个模块以及他们之间的依赖关系,根据entry或分包配置生成代码块chunk;
- 输出完成:输出所有的chunk到文件系统;
webapck中什么是module ,什么是chunk,什么是bundle?
- Moudle:开发中的每个文件均可以看做是module,模块不局限于js,也包含css,图片等
- Chunk: webpack在进行模块的依赖分析时,被分割出来的代码块就是一个chunk,一个 chunk 由多个模块组合而成,用于代码的合并和分割
- Bundle:经过webpack打包后生成的文件就是bundle
Loader和Plugin有什么区别?
- Loader: 因为webpack本身只能处理js和json类型的文件,无法解析其他类型的文件,loader可以让webpack拥有了解析其它类型文件的能力。loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果
- Plugin 为插件的意思,Plugin 可以扩展 webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,帮助 webpack 做一些事情。
webpack有哪些常用的Loader
- file-loader:把文件输出到⼀个文件夹中,在代码中通过相对 URL 去引⽤输出的⽂件
- 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 常见的plugin有哪些
- ProvidePlugin:自动加载模块,代替require和import
- html-webpack-plugin可以根据模板自动生成html代码,并自动引用css和js文件
- extract-text-webpack-plugin 将js文件中引用的样式单独抽离成css文件
- DefinePlugin 编译时配置全局变量,这对开发模式和发布模式的构建允许不同的行为非常有用。
- HotModuleReplacementPlugin 热更新
- optimize-css-assets-webpack-plugin 不同组件中重复的css可以快速去重
- webpack-bundle-analyzer 一个webpack的bundle文件分析工具,将bundle文件以可交互缩放的treemap的形式展示。
- compression-webpack-plugin 生产环境可采用gzip压缩JS和CSS
- happypack:通过多进程模型,来加速代码构建
- clean-wenpack-plugin 清理每次打包下没有使用的文件
- speed-measure-webpack-plugin:可以看至U每个Loader和Plugin执行耗时(整个扌丁包耗时、每个Plugin和 Loader 耗时)
- webpack-bundle-analyzer:可视化Webpack输出文件的体积(业务组件、依赖第三方模块)
webpack 插件如何实现
- webpack本质是一个事件流机制,核心模块:tabable(Sync + Async)Hooks 构造出 === Compiler(编译) + Compiletion(创建bundles)
- compiler对象代表了完整的webpack环境配置。这个对象在启动webpack时被一次性建立,并配置好所有可操作的设置,包括options、loader和plugin。当在webpack环境中应用一插件时,插件将收到此compiler对象的引用。可以使用它来访问webpack的主环境
- compilation对象代表了一次资源版本构建。当运行webpack开发环境中间件时,每当检测到一个文件变化,就会创建一个新的compilation,从而生成一个新的编译资源。一个compilation对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态的信息。compilation对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用
- 创建一个插件函数,在其prototype上定义apply方法,指定一个webpack自身的事件钩子
- 函数内部处理webpack内部实例的特定数据
- 处理完成后,调用webpack提供的回调函数
如何webpack来优化前端性能?
webpack的优化前端性能有两方面
1.构建速度(提升开发效率)
2.打包体积(打包的结果在浏览器运⾏快速⾼效)
- 构建速度方面的优化
- 对于loader中test匹配的规则使用include/exclude来减小文件的搜索范围
- 设置resolve.alais的别名,减少路径的复杂度
- 优化resolve.extensions 使其可以快速查找引用文件的后缀名
- 使用externals对第三方库不进行打包,需配合CDN使用
- 设置oneof,打包时每个文件都会经过所有的loader处理,虽然经过test的正则没有匹配上,但还是需要过一遍,比较耗时,使用oneof后,匹配到满足条件的loader后就停止继续匹配其它的loader了
- 使用noparse 忽略未采用模块化的文件,不进行递归解析处理
- 使用thread-loader,对于耗时的模块开启多进程构建
- 使用cache-loader的缓存机制,可以有效的提高二次构建速度
2.打包体积方面的优化。
- 压缩代码:除多余的代码、注释、简化代码的写法等等⽅式。可以利⽤webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS件, 利⽤ cssnano (css-loader?minimize)来压缩css
- 利⽤CDN加速: 在构建过程中,将引⽤的静态资源路径修改为CDN上对应的路径。可以利⽤webpack对于 output 参数和各loader的 publicPath 参数来修改资源路径
- Tree Shaking: 将代码中永远不会⾛到的⽚段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现
- Code Splitting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存
- 提取公共第三⽅库: SplitChunksPlugin插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码
webpack的占位符[hash],[chunkhash],[contenthash] 有什么区别和联系。
- [hash]:是整个项目的hash值,其根据每次编译内容计算获得,每次编译以后都会生成新的hash,即修改任何文件都会致使全部文件的hash发生改变;在一个项目中虽然入口不一样,可是hash是相同的;hash没法实现前端静态资源在浏览器上长缓存,这时候应该使用chunkhashwebpack
- [chunkhash]:根据不一样的入口文件(entry)进行依赖文件解析,构建对应的chunk,生成相应的hash;只要组成entry的模块文件没有变化,则对应hash也是不变的,因此通常项目优化时,会将公共代码库拆分到一块儿,由于公共代码库代码变更较少的,使用chunkhash能够发挥最长缓存的作用
- [contenthash]:使用chunkhash存在一个问题,当在一个js文件引入css文件,编译后他们的hash是相同的。并且,只要js文件内容发生改变,与其关联的css文件hash也会改变,针对这种状况,能够把css从js中抽离出来并使用contenthash。