webpack面试题

webpack官网https://webpack.js.org/
webpack中文网https://www.webpackjs.com/

  1. webpack是什么

webpack是一个打包模块化javascript的工具,在webpack里一切文件皆模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合成的文件,webpack专注构建模块化项目。
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。
官网的图片形象的展示了webpack的定义

  1. Webpack 五个核心概念

     1、Entry: 入口(Entry)指示webpack以那个文件为入口起点开始打包,分析构建内部依赖。
     2、Output:输出(Output)指示webpack打包后的资源bundles输出到哪里去,以及如何命名。
     3、Loader:Loader让Webpack能够去处理那些非js文件。
     4、Plugins:插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。
     5、Mode:模式(Mode)指示Webpack使用相应模式的配置。配置分为development(开发模式)和production(生产模式)。
    
  2. webpack常用的loader和插件有什么

loader用于加载某些资源文件。因为webpack本身只能打包common.js规范的js文件,对于其他资源如css,img等,是没有办法加载的,这时就需要对应的loader将资源转化,从而进行加载。使wenbpack拥有加载和解析非js文件的能力

plugin用于扩展webpack的功能。不同于loader,plugin的功能更加丰富,比如压缩打包,优化,不只局限于资源的加载。

	常用loader:
	1. file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
	2. url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
	3. source-map-loader:加载额外的 Source Map 文件,以方便断点调试
	4. image-loader:加载并且压缩图片文件
	5. babel-loader:把 ES6 转换成 ES5
	6. css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
	7. style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
	8. eslint-loader:通过 ESLint 检查 JavaScript 代码
	常用plugin:
	9. html-webpack-plugin:自动生成html文件,并引入打包生成的js文件到生成的html文件中
	10. clean-webpack-plugin:自动清除上一次打包的dist文件
	11. webpack-dev-server:不需要刷新浏览器的情况下,数据变化了页面自动变化
	12. UglifyJsPlugin:压缩js
	13. define-plugin:定义环境变量
	14. terser-webpack-plugin:通过TerserPlugin压缩ES6代码
	15. mini-css-extract-plugin:分离css文件
	16. happypack:实现多线程加速编译
  1. webpack与grunt、gulp的不同?
    Webpack与Gulp、Grunt没有什么可比性,它可以看作模块打包机,通过分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。

他们的工作方式也有较大区别:

Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。

Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。

grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。

webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。

所以总结一下:

从构建思路来说
gulp和grunt需要开发者将整个前端构建过程拆分成多个Task,并合理控制所有Task的调用关系
webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工

对于知识背景来说
gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路

  1. webpack有哪些优点

    1. 专注于处理模块化的项目,能做到开箱即用,一步到位
    2. 可通过plugin扩展,完整好用又不失灵活
    3. 使用场景不局限于web开发
    4. 社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展
    5. 良好的开发体验
    6. webpack 是以 commonJS (CommonJS是一种被广泛使用的js模块化规范,核心思想是通过require方法来同步加载依赖的其他模块,通过module.exports导出需要暴露的接口。)的形式来书写脚本的,方便旧项目进行代码迁移。
  2. webpack的缺点

webpack的缺点是只能用于采用模块化开发的项目

  1. 分别介绍bundle,chunk,module是什么

    1. bundle:是由webpack打包出来的文件,
    2. chunk:代码块,一个chunk由多个模块组合而成,用于代码的合并和分割。
    3. module:是开发中的单个模块,在webpack的世界,一切皆模块,一个模块对应一个文件,webpack会从配置的 entry中递归开始找出所有依赖的模块。
  2. 分别介绍什么是loader?什么是plugin?

loader:模块转换器,用于将模块的原内容按照需要转成你想要的内容
plugin:在webpack构建流程中的特定时机注入扩展逻辑,来改变构建结果,是用来自定义webpack打包过程的方式,一个插件是含有apply方法的一个对象,通过这个方法可以参与到整个webpack打包的各个流程(生命周期)。

  1. 什么 是模块热更新?

模块热更新是webpack的一个功能,他可以使得代码修改过后不用刷新浏览器就可以更新,是高级版的自动刷新浏览器。
devServer中通过hot属性可以控制模块的热替换

  1. 什么是Tree-shaking

Tree-shaking可以用来剔除javascript中不用的死代码,它依赖静态的es6模块化语法,例如通过哦import 和export 导入导出,Tree-shaking最先在rollup中出现,webpack在2.0中将其引入,css中使用Tree-shaking需要引入Purify-CSS

  1. 通过webpack处理长缓存

浏览器在用户访问页面的时候,为了加快加载速度,会对用户访问的静态资源进行存储,但是每一次代码升级或是更新,都需要浏览器去下载新的代码,最方便和简单的更新方式就是引入新的文件名称。在webpack中可以在output纵输出的文件指定chunkhash,并且分离经常更新的代码和框架代码。通过NameModulesPlugin或是HashedModuleIdsPlugin使再次打包文件名不变。

  1. 如何提高webpack的构建速度

    1. 通过externals配置来提取常用库
    2. 利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
    3. 使用Happypack 实现多线程加速编译
  2. webpack的构建流程是什么?

    1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
    2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
    3. 确定入口:根据配置中的 entry 找出所有的入口文件;
    4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
    5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
    6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
    7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
  3. 如何利用webpack来优化前端性能?(提高性能和体验)

压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径。CDN 又叫内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数–optimize-minimize来实现
提取公共代码。

  1. 如何提高webpack的构建速度

    1.多入口情况下,使用CommonsChunkPlugin来提取公共代码。
    2.使用Happypack 实现多线程加速编译。

    1. 使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度
    2. 使用Tree-shaking和Scope Hoisting来剔除多余代码
  2. webpack的基本功能和工作原理?

    1. 代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
    2. 文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等
    3. 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
    4. 模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
    5. 自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
    6. 代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
    7. 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
  3. webpack打包原理

1、把一切都视为模块:不管是 CSS、JS、Image 还是 HTML 都可以互相引用,通过定义 entry.js,对所有依赖的文件进行跟踪,将各个模块通过 loader 和 plugins 处理,然后打包在一起。
按需加载:打包过程中 Webpack 通过 Code Splitting 功能将文件分为多个 chunks,还可以将重复的部分单独提取出来作为 commonChunk,从而实现按需加载。把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载

  1. 如何自动生成webpack配置文件?

webpack-cli、vue-cli

  1. 什么是模热更新?有什么优点?

模块热更新是webpack的一个功能,它可以使得代码修改之后,不用刷新浏览器就可以更新。在应用过程中替换添加删出模块,无需重新加载整个页面,是高级版的自动刷新浏览器。
优点:只更新变更内容,以节省宝贵的开发时间。调整样式更加快速,几乎相当于在浏览器中更改样式

  1. webpack-dev-server 和 http服务器的区别

webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,比传统的http服务对开发更加有效。

  1. webpack3和webpack4的区别

    1. mode/–mode参数,新增了mode/–mode参数来表示是开发还是生产(development/production)
      production 侧重于打包后的文件大小,development侧重于goujiansud
    2. 移除loaders,必须使用rules(在3版本的时候loaders和rules 是共存的但是到4的时候只允许使用rules)
    3. 移除了CommonsChunkPlugin (提取公共代码),用optimization.splitChunks和optimization.runtimeChunk来代替
    4. 支持es6的方式导入JSON文件,并且可以过滤无用的代码
  2. 说一下webpack构建流程

Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
Plugin:扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
Output:输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果。

Webpack 启动后会从 Entry 里配置的 Module 开始递归解析 Entry 依赖的所有 Module。 每找到一个 Module, 就会根据配置的 Loader 去找出对应的转换规则,对 Module 进行转换后,再解析出当前 Module 依赖的 Module。 这些模块会以 Entry 为单位进行分组,一个 Entry 和其所有依赖的 Module 被分到一个组也就是一个 Chunk。最后 Webpack 会把所有 Chunk 转换成文件输出。 在整个流程中 Webpack 会在恰当的时机执行 Plugin 里定义的逻辑。

  1. webpack单页面转多页面

a. 首先我们在根目录创建一个 entries 文件夹,把不同入口的 router、 store、 main.js 都放这里,每个入口相关单独放在一个文件夹;
b. 在 src 目录下建立一个 common 文件夹,用来存放多入口共用的组件等;

.	
├── build    # 没有改动	
├── config   # 没有改动	
├── entries  # 存放不同入口的文件	
│   ├── entry1	
│   │   ├── router       # entry1 的 router	
│   │   │   └── index.js	
│   │   ├── store        # entry1 的 store	
│   │   │   └── index.js	
│   │   ├── App.vue      # entry1 的根组件	
│   │   ├── index.html   # entry1 的页面模版	
│   │   └── main.js      # entry1 的入口	
│   └── entry2	
│       ├── router	
│       │   └── index.js	
│       ├── store	
│       │   └── index.js	
│       ├── App.vue	
│       ├── index.html	
│       └── main.js	
├── src	
│   ├── assets	
│   │   └── logo.png	
│   ├── common          # 多入口通用组件	
│   │   └── CommonTemplate.vue	
│   └── components	
│       ├── HelloWorld.vue	
│       ├── test1.vue	
│       └── test2.vue	
├── static	
├── README.md	
├── index.html	
├── package-lock.json	
└── package.json

c. 然后我们在 build/utils 文件中加两个函数,分别用来生成 webpack 的 entry 配置和 HtmlWebpackPlugin 插件配置,由于要使用 node.js 来读取文件夹结构,因此需要引入 fs、 glob 等模块:

// build/utils	
const fs = require('fs')	
const glob = require('glob')	
const merge = require('webpack-merge')	
const HtmlWebpackPlugin = require('html-webpack-plugin')	
const ENTRY_PATH = path.resolve(__dirname, '../entries')	
// 多入口配置,这个函数从 entries 文件夹中读取入口文件,装配成webpack.entry配置	
exports.entries = function() {	
  const entryFiles = glob.sync(ENTRY_PATH + '/*/*.js')	
  const map = {}	
  entryFiles.forEach(filePath => {	
    const filename = filePath.replace(/.*\/(\w+)\/\w+(\.html|\.js)$/, (rs, $1) => $1)	
    map[filename] = filePath	
  })	
  return map	
}	
// 多页面输出模版配置 HtmlWebpackPlugin,根据环境装配html模版配置	
exports.htmlPlugin = function() {	
  let entryHtml = glob.sync(ENTRY_PATH + '/*/*.html')	
  let arr = []	
  entryHtml.forEach(filePath => {	
    let filename = filePath.replace(/.*\/(\w+)\/\w+(\.html|\.js)$/, (rs, $1) => $1)	
    let conf = {	
      template: filePath,	
      filename: filename + '.html',	
      chunks: [filename],	
      inject: true	
    }	
    // production 生产模式下配置	
    if (process.env.NODE_ENV === 'production') {	
      conf = merge(conf, {	
        chunks: ['manifest', 'vendor'],	
        minify: {	
          removeComments: true,	
          collapseWhitespace: true,	
          removeAttributeQuotes: true	
        },	
        chunksSortMode: 'dependency'	
      })	
    }	
    arr.push(new HtmlWebpackPlugin(conf))	
  })	
  return arr	
}

稍微解释一下这两个函数:

exports.entries 函数从 entries 文件夹中找到二级目录下的 JS 文件作为入口文件,并且将二级目录的文件夹名作为 key,生成这样一个对象: {“entry1”:"/multi-entry-vue/entries/entry1/main.js"},多个入口情况下会有更多键值对;

exports.htmlPlugin 函数和之前函数的原理类似,不过组装的是 HtmlWebpackPlugin 插件的配置,生成这样一个数组,可以看到和我们手动设置的配置基本一样,只不过现在是根据文件夹结构来生成的:

// production 下	
[	
  {	
    template: "/multi-entry-vue/entries/entry1/index.html",	
    chunks: ['manifest', 'vendor', 'entry1'],	
    filename: "entry1.html",	
    chunksSortMode: 'dependency'	
  },	
  { ... }   // 下一个入口的配置	
]

有了这两个根据 entries 文件夹的结构来自动生成 webpack 配置的函数,下面来改一下 webpack 相关的几个配置文件:

// build/webpack.base.conf.js	
module.exports = {	
  entry: utils.entries(),   // 使用函数生成 entry 配置	
  output: {	
    path: config.build.assetsRoot,	
    filename: '[name].js',	
    publicPath: process.env.NODE_ENV === 'production'	
      ? config.build.assetsPublicPath	
      : config.dev.assetsPublicPath	
  }	
}
// build/webpack.dev.conf.js	
// const HtmlWebpackPlugin = require('html-webpack-plugin')  // 不需要了	
const devWebpackConfig = merge(baseWebpackConfig, {	
  devServer: {	
    historyApiFallback: {	
      rewrites: [        // 别忘了把 devserver 的默认路由改一下	
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'entry1.html') },	
      ],	
    }	
  },	
  plugins: [	
    // https://github.com/ampedandwired/html-webpack-plugin	
    // new HtmlWebpackPlugin({	
    //   filename: 'index.html',	
    //   template: 'index.html',	
    //   inject: true	
    // }),                   // 注释掉原来的 HtmlWebpackPlugin 配置,使用生成的配置	
  ].concat(utils.htmlPlugin())	
})

现在我们再 npm run build,看看生成的目录是什么样的:

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值