webpack
-
webpack是一个打包工具 用来管理各个模块之间错综复杂的依赖关系 使开发更加编辑 可以通过loader转换文件,通过plugin扩展功能。
-
webpack基本功能:
- 代码转换
- 文件优化: 压缩 JavaScript、CSS、HTML 代码,压缩合并图片等
- 代码校验
- 自动发布
- 模块合并: 在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
- 自动刷新
- 代码分割: 提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
-
webpack工作原理:
- entry 从入口文件中 开始解析入口文件所依赖的module
- 每找到一个module,就会根据配置的loader去找对应的转换规则
- 对module进行转换后,再解析出当前module依赖的module
- 这些模块会以entry为单位分组,一个entry和其所有依赖的module被分到一个组Chunk
- 最后webpack会把所有Chunk转换成文件输出
-
webpack打包原理
将所有依赖打包成一个bundle.js,通过代码分割成单元片段按需加载
-
什么是bundle,chunk,module
bundle是webpack打包出来的文件
chunk是webpack在进行模块的依赖分析的时候,代码分割出来的代码块
module是开发中的单个模块
-
webpack-dev-server和http服务器如nginx有什么区别
webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,相比传统http服务器开发更加简单高效
-
什么是模块热更新 其原理是啥
webpack的一个功能,可以使代码修改后不用刷新浏览器就自动更新,高级版的自动刷新浏览器
分析:(1)第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块重新编译打包,并将打包后的代码通过简单的 JavaScript 对象保存在内存中。
(2)第二步是 webpack-dev-server 和 webpack 之间的接口交互,而在这一步,主要是 dev-server 的中间件 webpack-dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API对代码变化进行监控,并且告诉 webpack,将代码打包到内存中。
(3)第三步是 webpack-dev-server 对文件变化的一个监控,这一步不同于第一步,并不是监控代码变化重新打包。当我们在配置文件中配置了devServer.watchContentBase 为 true 的时候,Server 会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload。注意,这儿是浏览器刷新,和 HMR 是两个概念。
(4)第四步也是 webpack-dev-server 代码的工作,该步骤主要是通过 sockjs(webpack-dev-server 的依赖)在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据这些 socket 消息进行不同的操作。当然服务端传递的最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
(5)webpack-dev-server/client 端并不能够请求更新的代码,也不会执行热更模块操作,而把这些工作又交回给了 webpack,webpack/hot/dev-server 的工作就是根据 webpack-dev-server/client 传给它的信息以及 dev-server 的配置决定是刷新浏览器呢还是进行模块热更新。当然如果仅仅是刷新浏览器,也就没有后面那些步骤了。
(6)HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的 hash 值,它通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个 json,该 json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块代码。这就是上图中 7、8、9 步骤。
(7)而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
(8)最后一步,当 HMR 失败后,回退到 live reload 操作,也就是进行浏览器刷新来获取最新打包代码。
-
dev-server是怎么跑起来的
webpack-dev-server支持两种模式来自动刷新页面
-
iframe模式: 页面放在iframe模式中 只要在页面中输入url http:localhost:8080/webpack-dev-server/index.html
-
inline模式 将webpack-dev-server的入口放到boundle中 inline模式下url不用发生变化,但启动inline模式分两种情况
在启动命令中配置–inline 或 在 webpack.config.js 中 配置devServer:{inline:true}
-
-
使用过webpack里面哪些plugin和loader 有啥区别
loader: css-loader file-loader babel-loader url-loader eslint-load
plugins: html-webpack-plugin clean-webpack-plugin uglifyjs-webpack-plugin(通过UglifyJS去压缩js代码) commons-chunk-plugin(提取公共代码)
区别:
- loader在module.rule中配置。类型为数组,每一项都是Object;plugin是单独配置的,类型为数组,每一项都是plugin实例,参数通过构造函数传入
- loader是用来告诉webpack如何转换某一类型的文件 plugin 功能比较强大 用来扩展webpack 功能的
-
什么是Tree-shaking?CSS可以Tree-shaking?
Tree-shaking是指在打包中取出那些引入了但在代码中没有被用到的死代码。webpack中通过uglifysPlugin来Tree-shaking JS。CSS需要使用purify-CSS
-
怎么配置单页应用?怎么配置多页应用
单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可
多页应用也可以在入口文件中配置 入口文件是一个对象 对象里面对应着多个入口文件 也可以通过AutoWebPlugin来完成简单自动化的构建
-
什么是长缓存 在webpack中如何做到长缓存优化
长缓存: 我们在访问页面时候 为了加快用户体验速度 需要对我们访问的资源进行浏览器缓存
webpack 长缓存 :
-
访问的文件 不用[hash],而使用[chunkhash] 每次浏览器更新只更新你修改的文件 其余文件不更新 也即浏览器随着内容更新 不随着编译更新
-
css文件不受js模块变化影响 css文件hash使用contenthash,这样不受js模块变化影响
-
提取vendor: 单独提取第三文件 使其作为稳定的版本 利用浏览缓存减少请求次数 常用的提取第三方库的方法有两种
CommonsChunkPlugin DLLPlugin
CommonsChunkPlugin 是每次打包时候都要把第三方库也运行打包一次 DLLPlugin 每次打包只打包项目文件 只需要引用第一次打包好的压缩文件就可以CommonsChunkPlugin: const vue = require('vue') { entry: { // bundle是我们要打包的项目文件的导出名字, app是入口js文件 bundle: 'app', // vendor就是我们要打包的第三方库最终生成的文件名,数组里是要打包哪些第三方库, 如果不是在node——modules里面,可以填写库的具体地址 vendor: ['vue'] }, output: { path: __dirname + '/bulid/', // 文件名称 filename: '[name].js' }, plugins: { // 这里实例化webpack.optimize.CommonsChunkPlugin构造函数 // 打包之后就生成vendor.js文件 new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js') } } DLLPlugin webpack.dll.config.js文件配置如下 const webpack = require('webpack') const library = '[name]_lib' const path = require('path') module.exports = { entry: { vendors: ['vue', 'vuex'] }, output: { filename: '[name].dll.js', path: 'dist/', library }, plugins: [ new webpack.DllPlugin({ path: path.join(__dirname, 'dist/[name]-manifest.json'), // This must match the output.library option above name: library }), ], } webpack.config.js 文件配置如下 const webpack = require('webpack') module.exports = { entry: { app: './src/index' }, output: { filename: 'app.bundle.js', path: 'dist/', }, plugins: [ new webpack.DllReferencePlugin({ context: __dirname, manifest: require('./dist/vendors-manifest.json') }) ]
}
-
保证module Id稳定 模块的新增或删除,会导致其后面的所有模块id重新排序,为避免这个问题,不使用数字作为模块id,改用文件路径的hash值,使用HashedModuleIdsPlugin可以解决
-
如何在vue项目中实现按需加载?
经常会引入现成的UI组件库如ElementUI、iView等,但是他们的体积和他们所提供的功能一样,是很庞大的。
不过很多组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import 安装以上插件后,在.babelrc配置中或babel-loader的参数中进行设置,即可实现组件按需加载了。 -
webpack和gulp的不同
- webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等
- webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,
用Plugin来扩展webpack功能 而gulp是基本task的 一个文件就是一个ask 多个任务就构成了web的整个构建流程
简单来说 gulp侧重于task的 而webpack是根据入口文件中的module来来层层解析 用babel转换文件 plugin扩展功能
-
利用webpack来优化前端性能
webpack优化 从两点来说你 一个是速度 一个是体积-
压缩代码 删除多余的代码、注释、简化代码的写法等等方式 可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件 webpack-uglify-parallel(多线程的)优于UglifyJsPlugin (体积)
-
利用CDN加速 在构建过程中,将引用的静态资源路径修改为CDN上对应的路径 (速度)
-
提取第三方公共文件 减少浏览器的请求次数 (通过externals配置来提取常用库) (速度)
-
tree shaking: 删除无用的代码 (体积)
-
打包的文件名不用hash 而用chunkhash (速度)
-
路由按需加载 (速度)
-
多入口情况下 使用commonsChunkPlugin来提取公共代码 (速度)
-
Scope Hoisting: 打包后的文件存在大量的闭包文件 有很多都是重复的 Scope Hoisting分析出模块之间的依赖关系,尽可能的把打散的模块合并到一个函数中去 从而使体积变小 代码在运行时候 函数作用域变少了 所以内存开销也随之变小(体积)
-
include/exclude exclude: 指定哪些文件通过或不通过loader解析 include: 需要被loader 处理的文件或文件夹
-
resolve解析: 我们一般是根据入口文件来找模块之间的依赖关系的 而resolve就是告诉我们怎么去寻找文件
let path = require('path'); //node的path模块 module.exports = { mode: 'development',//模式,默认两种 production和development entry: './src/index.js', //入口 output: { filename: 'bundle.js', //打包后的文件名,名字随便起 path: path.resolve(__dirname, 'build') // 必须是绝对路径 }, module: { //配置loader rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader' ] } ] }, resolve: { //解析第三方包 modules: [ //配置 Webpack 去哪些目录下寻找第三方模块 path.resolve('node_modules'),//只从node_modules下面找 //path.resolve('others') //还可以是自定义的其他目录 ], mainFields:['style','main'], // 配置加载顺序 extensions: ['.css', '.js', '.json'] // 省略扩展名,比如:import {xx} from './src/index' alias:{ // 设置别名的 '@':path.resolve(__dirname,'src') } } }
-
cdn缓存: 我们打包后 index.html文件中均会引入对应的js css 图片文件 是相对路径 所以我们可以定义一个域名 来指向之前的服务器 这样就可以用域名+对应路径的形式来访问index.html 这在webpack中可以实现 output中添加一个publicPath配置 它可以指定css/js/img的URL前缀 从而实现替换cdn链接的目的
-
-
npm打包时需要注意哪些
- 要支持CommonJS模块化规范,所以要求打包后的最后结果也遵守该规则
- 最好是用es5编写 然后进行转换
- Npm包大小应该是尽量小
- 发布的模块不能将依赖的模块也一同打包,应该让用户选择性的去自行安装。这样可以避免模块应用者再次打包时出现底层模块被重复打包的情况