webpack面试题

 webpack文档链接

https://www.webpackjs.com/

1.webpack五大核心

  • Entry - 入口

Entry 指示 Webpack 从哪个模块开始构建内部依赖图,以及如何将所有依赖项连接在一起。

  • Output - 输出

Output 定义了 Webpack 构建的输出文件的位置和文件名。

  • Loader - 加载器

Loader 用于对模块的源代码进行转换,以便于 Webpack 处理。例如,当 Webpack 遇到一个 “.css” 文件时,使用 “css-loader” 和 “style-loader” 将其转换为 JavaScript 代码以便于在浏览器中呈现样式。

  • Plugin - 插件

Plugin 在 Webpack 的构建过程中扮演一个关键的角色,它可以完成各种各样的任务,例如压缩代码、拷贝文件到输出目录、创建全局变量等等。

  • Mode - 模式

Mode 是 Webpack 4 引入的一个新特性,它提供了三种不同的构建模式,即 “development”、“production” 和 “none”,分别对应着开发模式、生产模式和不设置模式。

以下是webpack.config.js中的配置

 

const path = require('path');  
const HtmlWebpackPlugin = require('html-webpack-plugin');  
const TerserPlugin = require('terser-webpack-plugin');  
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');  
  
module.exports = {  
  // Entry  
  entry: './src/index.js', // 指定入口文件  
  
  // Output  
  output: {  
    filename: 'bundle.js', // 输出文件名  
    path: path.resolve(__dirname, 'dist'), // 输出目录  
    clean: true, // 在构建前清空输出目录,Webpack 5+ 新增  
  },  
  
  // Mode  
  mode: 'production', // 设置模式为生产模式  
  
  // Module  
  module: {  
    rules: [  
      {  
        test: /\.css$/, // 正则表达式匹配所有.css文件  
        use: ['style-loader', 'css-loader'], // 使用style-loader和css-loader处理CSS文件  
      },  
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/, // 匹配图片文件
        type: 'asset/resource', // 使用 asset 模块处理图片
      },
      {
        test: /\.js$/, // 匹配 JavaScript 文件
        exclude: /node_modules/, // 排除 node_modules 目录
        use: {
          loader: 'babel-loader', // 使用 Babel 加载器转换 ES6 到 ES5
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
      // 示例:为.js文件启用ESLint(可选)  
      // {  
      //   test: /\.js$/,  
      //   exclude: /node_modules/,  
      //   use: {  
      //     loader: 'eslint-loader',  
      //     options: {  
      //       // eslint options (if necessary)  
      //     },  
      //   },  
      // },  
    ],  
  },  
  
  // Plugins  
  plugins: [  
    // 创建一个HTML文件来承载所有生成的bundle  
    new HtmlWebpackPlugin({  
      template: './src/index.html', // 使用src目录下的index.html作为模板  
    }),  
    // 示例:优化JS和CSS文件(可选,视需求而定)  
    // 在生产模式下,Webpack 会自动应用这些优化,但也可以显式定义  
    // new TerserPlugin({  
    //   terserOptions: {  
    //     // terser options (if necessary)  
    //   },  
    // }),  
    // new CssMinimizerPlugin(),  
  ],  
  
  // Optimization  
  optimization: {  
    minimize: true, // 开启代码压缩  
    minimizer: [  
      // 使用自定义的minimizer配置  
      // 可以注释掉,因为Webpack默认已经配置好了  
      // new TerserPlugin({  
      //   // terser options  
      // }),  
      // new CssMinimizerPlugin(),  
    ],  
  },  
  
  // DevServer(开发服务器配置,通常只在开发模式下使用)  
  // 注意:此配置不包含在mode设置中  
  devServer: {  
    contentBase: './dist', // 告诉服务器从哪里提供内容  
    hot: true, // 启用热模块替换  
    contentBase: path.join(__dirname, 'dist'), // 设置静态文件根目录
    compress: true, // 开启 gzip 压缩
    port: 9000, // 设置端口号
  },  
};  
  
// 注意:在开发模式下,你可能需要调整mode为'development',并可能移除或调整optimization中的minimize选项

2.谈谈你对Webpack的理解(Webpack是什么?)

Webpack 是一个 静态模块打包器,可以分析各个模块的依赖关系,项目中的所有资源皆为模块,通过分析模块间的依赖关系,在其内部递归构建出一个依赖关系图,其中包含应用程序需要的每个模块,然后将这些模块打包成一个或多个 bundle。最终编绎输出模块为 HTML、JavaScript、CSS 以及各种静态文件(图片、字体等)。

Webpack 的工作流程大致如下:

  1. Webpack 从配置的入口点开始,分析应用程序的依赖关系。
  2. Webpack 使用加载器(loaders)将非 JavaScript 文件转换为模块。
  3. Webpack 递归地构建一个依赖关系图,该图包含了应用程序需要的每个模块。
  4. Webpack 将所有这些模块打包成一个或多个 bundle。
  5. 在最后一步,Webpack 可以将这些 bundle 输出到文件系统上。

3. Webpack的打包过程/打包原理/构建流程?

  • 初始化:启动构建,读取与合并配置参数,加载plugin,实例化Compiler
  • 编译:从Entry出发,针对每个Module串行调用对应的Loader去翻译文件中的内容,再找到该Module依赖的Module,递归的进行编译处理
  • 输出:将编译后的Module组合成Chunk,将Chunk转换成文件,输出到文件系统中

4. loader的作用(常见的loader有哪些)

作用

webpack中的loader是一个函数,主要为了实现源码的转换,所以loader函数会以源码作为参数,比如,将ES6转换为ES5,将less转换为css,然后再将css转换为js,以便能嵌入到html文件中。

默认情况下,webpack只支持对js和json文件进行打包,但是像css、html、png等其他类型的文件,webpack则无能为力。因此,就需要配置相应的loader进行文件内容的解析转换。

有哪些常见的Loader?他们是解决什么问题的?

  • image-loader:加载并且压缩图片文件。
  • less-loader:加载并编译 LESS 文件。
  • sass-loader:加载并编译 SASS/SCSS 文件。
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性,使用css-loader必须要配合使用style-loader。
  • style-loader:用于将 CSS 编译完成的样式,挂载到页面的 style 标签上。需要注意 loader 执行顺序,style-loader 要放在第一位,loader 都是从后往前执行。
  • babel-loader:把 ES6 转换成 ES5
  • postcss-loader:扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀。
  • eslint-loader:通过 ESLint 检查 JavaScript 代码。
  • vue-loader:加载并编译 Vue 组件。
  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
  • url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)。
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试。

5. plugin的作用(常见的plugin有哪些)

作用

webpack中的plugin赋予其各种灵活的功能,例如打包优化、资源管理、环境变量注入等,它们会运行在webpack的不同阶段(钩子 / 生命周期),贯穿了webpack整个编译周期。目的在于解决 loader 无法实现的其他事。

举例说明(代码)

 HtmlWebpackPlugin

  • 作用:自动生成HTML文件,并将打包后的文件(如JavaScript、CSS)自动引入。这对于单页应用(SPA)特别有用,可以保证生成的HTML文件总是引用最新的打包文件。
  • 示例:在Webpack配置文件中配置HtmlWebpackPlugin,指定模板文件后,Webpack会自动生成一个包含打包后文件引用的HTML文件。
const HtmlWebpackPlugin = require('html-webpack-plugin');  
module.exports = {  
  // 其他配置...  
  plugins: [  
    new HtmlWebpackPlugin({  
      template: './src/index.html', // 指定模板文件  
      filename: 'index.html', // 输出的HTML文件名  
    }),  
  ],  
};

TerserWebpackPlugin

作用:压缩JavaScript代码,删除无用的空格、注释和变量名,以减少文件体积,提高加载速度

示例:在Webpack配置文件中配置TerserWebpackPlugin后,Webpack会在构建过程中自动压缩打包后的JavaScript文件。

const TerserPlugin = require('terser-webpack-plugin');  
module.exports = {  
  // 其他配置...  
  optimization: {  
    minimize: true,  
    minimizer: [new TerserPlugin({  
      // TerserPlugin 选项...  
    })],  
  },  
};

CleanWebpackPlugin

作用:在每次构建前清空输出目录,确保每次构建都是基于一个干净的环境,避免旧文件残留导致的问题。

示例:在Webpack配置文件中配置CleanWebpackPlugin后,每次运行构建命令时,该插件都会先清空指定的输出目录,然后再进行构建。

const { CleanWebpackPlugin } = require('clean-webpack-plugin');  
module.exports = {  
  // 其他配置...  
  plugins: [  
    new CleanWebpackPlugin(), // 默认会清理`output.path`指定的目录  
    // 或者你可以传递一个配置对象来自定义行为  
    // new CleanWebpackPlugin({  
    //   cleanOnceBeforeBuildPatterns: ['**/*', '!.gitkeep'], // 自定义清理模式  
    // }),  
  ],  
};

CopyWebpackPlugin

作用:复制静态资源文件(如图片、字体文件等)到指定的输出目录。这对于需要将非代码资源也打包到发布目录中的场景非常有用。

示例:在Webpack配置文件中配置CopyWebpackPlugin,并指定需要复制的资源和目标目录后,Webpack会在构建过程中自动将指定资源复制到目标目录。

const CopyWebpackPlugin = require('copy-webpack-plugin');  
module.exports = {  
  // 其他配置...  
  plugins: [  
    new CopyWebpackPlugin({  
      patterns: [  
        { from: 'source', to: 'dest' }, // 将'source'目录下的所有内容复制到'dest'目录  
        // 你可以指定更复杂的模式,包括glob模式等  
      ],  
    }),  
  ],  
};

有哪些常见的Plugin?他们是解决什么问题的?

  • html-webpack-plugin:可以复制一个有结构的html文件,并自动引入打包输出的所有资源(JS/CSS)
  • clean-webpack-plugin:重新打包自动清空 dist 目录
  • mini-css-extract-plugin:提取 js 中的 css 成单独文件
  • optimize-css-assets-webpack-plugin:压缩css
  • uglifyjs-webpack-plugin:压缩js
  • commons-chunk-plugin:提取公共代码
  • define-plugin:定义环境变量

6.Webpack中Loader和Plugin的区别

运行时机

  • 1.loader运行在编译阶段
  • 2.plugins 在整个周期都起作用

使用方式

Loader:1.下载 2.使用

Plugin:1.下载 2.引用 3.使用

loader是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中;plugin赋予了webpack各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader无法实现的其他事。

在运行时机上,loader 运行在打包文件之前;plugin则是在整个编译周期都起作用。

在配置上,loader在module.rules中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性;plugin在 plugins中单独配置,类型为数组,每一项是一个 plugin 的实例,参数都通过构造函数传入。

7.webpack的热更新是如何做到的?说明其原理

热更新的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上webpack-dev-server与浏览器之间维护了一个websocket,当本地资源发生变化时,webpack-dev-server会向浏览器推送更新,并带上构建时的hash,让客户端与上一次资源进行对比。客户端对比出差异后会向webpack-dev-server发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向webpack-dev-server发起 jsonp 请求获取该chunk的增量更新。

简单理解Webpack 的热更新(Hot Module Replacement, HMR)是一种在开发过程中实时更新模块而不需刷新整个页面的技术。这对于提高开发效率非常有帮助,因为它允许开发者在编辑代码后立即看到结果,而不会丢失任何页面状态,比如表单数据或用户交互。

下面是以简单易懂的方式解释 HMR 的工作原理:

  1. WebSocket 建立连接: 当你启动 Webpack Dev Server 并开启 HMR 功能时,它会创建一个 WebSocket 连接。这个连接允许 Dev Server 和浏览器之间进行实时双向通信。

  2. 监听文件变化: Webpack Dev Server 会监听项目中的文件变化。当你修改了一个文件并保存时,Dev Server 会检测到这个变化。

  3. 增量构建: Webpack 不会重新构建整个项目,而是只构建那些发生改变的模块以及它们的依赖。这样可以显著减少构建时间。

  4. 发送更新信息: 构建完成后,Dev Server 通过 WebSocket 发送一个消息给浏览器,告诉它哪些模块已经被更新。

  5. 浏览器接收更新: 浏览器接收到这个消息后,知道哪些模块需要替换。它会卸载旧的模块,并加载新的模块。

  6. 模块替换: 浏览器会用新模块替换掉旧模块,但是不会刷新整个页面。这通常意味着只有改动的部分会被更新,而其他部分保持不变。

  7. 保留状态: 由于模块是在运行时被替换的,所以像组件的状态、变量的值等页面状态会被保留下来,用户不会感觉到页面有任何中断。

 // 插件配置
  plugins: [
    // 如果你想使用 HMR,通常需要引入 HotModuleReplacementPlugin
    new webpack.HotModuleReplacementPlugin(),
  ],

8.如何解决循环依赖问题

循环依赖是指两个或更多的模块直接或间接地相互引用对方,形成一个闭环的依赖关系。这种情况下,Webpack 等模块打包工具可能会遇到问题,因为它们无法确定正确的加载顺序。

原始代码示例(存在循环依赖)

当前为A文件

// 引入模块B  
import B from './B';  
export default class A {  
  constructor() {  
    console.log('A is created');  
    this.b = new B(); // 使用模块B  
  }  
}

当前为B文件

// 引入模块A  
import A from './A';  
export default class B {  
  constructor() {  
    console.log('B is created');  
    this.a = new A(); // 使用模块A  
  }  
}

可安装插件查找哪个出现了循环

1.终端安装 npm i circular-dependency-plugin -D

在 webpack 配置文件里添加 plugins 配置。

const CircularDependencyPlugin = require('circular-dependency-plugin')
export default {
  ...,
  plugins: [
    ...,
    new CircularDependencyPlugin(
      {
        exclude: /node_modules/,
        include: /src/,
        failOnError: false,
        allowAsyncCycles: false,
        cwd: process.cwd(),
      }
    ),
  ]
}

重启项目,在启动命令行里就能看到循环引用的警告信息,插件会帮你定位出问题的文件路径。

如何解决

创建一个C文件来放置共享数据

// 这里可以放置一些共享的数据或函数  
export default class C {  
  // 示例方法或数据  
  sharedData = 'This is shared data';  
}

A文件中引用C

import C from './C';  
export default class A {  
  constructor(c) {  
    console.log('A is created');  
    this.c = c; // 使用模块C  
  }  
}

B文件中引用C

import C from './C';  
export default class B {  
  constructor(c) {  
    console.log('B is created');  
    this.c = c; // 使用模块C  
  }  
}

9. 如何提高Webpack构建速度

1. 使用Webpack自带的缓存

Webpack 4+ 引入了文件系统缓存,可以在webpack.config.js中启用

module.exports = {  
  // ...  
  cache: {  
    type: 'filesystem', // 启用文件系统缓存  
    buildDependencies: {  
      config: [__filename] // 当webpack.config.js改变时,缓存失效  
    }  
  },  
  // ...  
};

2.使用thread-loader,cache-loader进行并行处理

thread-loader的主要目的是利用多核处理器的能力,通过将加载器的执行分发到多个工作线程中来加速构建过程。这对于 I/O 密集型或 CPU 密集型的任务特别有用,比如编译 TypeScript、Babel 转换、Sass 编译等。thread-loader 可以显著减少构建时间,尤其是在大型项目中。

npm install --save-dev thread-loader

 

module: {  
  rules: [  
    {  
      test: /\.js$/,  
      use: [  
        'thread-loader', // 放在耗时的loader之前  
        'babel-loader'  
      ]  
    }  
  ]  
}

cache-loader 的目标是避免重复执行相同的加载器任务。它会缓存加载器的结果,当同一个模块再次被加载时,如果缓存有效,cache-loader 将直接从缓存中读取结果,而不是重新执行加载器。这对于频繁构建的场景非常有帮助,因为它减少了不必要的计算和 I/O 操作。例如单页面使用

npm install --save-dev cache-loader

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: [
          'cache-loader', // 添加 cache-loader
          'babel-loader',
        ],
      },
    ],
  },
};

 一般情况下,推荐同时使用 thread-loader 和 cache-loaderthread-loader 放在 cache-loader 之后,这样可以先检查缓存,如果缓存有效则直接使用,否则再利用多线程加速加载器的执行。

{
  test: /\.jsx?$/,
  exclude: /node_modules/,
  use: [
    'cache-loader', // 缓存加载器结果
    {
      loader: 'thread-loader', // 使用多线程
      options: {
        workers: require('os').cpus().length - 1 // 根据 CPU 核心数量设置工作线程数
      }
    },
    'babel-loader' // 实际的代码转换加载器
  ]
}

3. 减少解析和编译时间

通过配置 resolve.alias 和 resolve.extensions 来优化模块解析,使用 babel-loader 的 cacheDirectory 选项来缓存编译结果

module.exports = {
  // ...
  resolve: {
    alias: {
      components: path.resolve(__dirname, 'src/components'),
      utils: path.resolve(__dirname, 'src/utils'),
    },
    extensions: ['.js', '.jsx', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true, // 开启缓存
          },
        },
      },
    ],
  },
};

4.压缩和最小化

  • Webpack 4+ 默认使用TerserPlugin进行JavaScript压缩,但如果你需要自定义配置,可能需要显式安装terser-webpack-plugin
  • 对于CSS,MiniCssExtractPlugin需要单独安装,以及可能的cssnano(如果用于进一步压缩CSS)。
npm install --save-dev terser-webpack-plugin mini-css-extract-plugin css-loader cssnano postcss-loader

(注意:cssnano通常作为PostCSS插件使用,因此需要postcss-loader

const TerserPlugin = require('terser-webpack-plugin'); // 如果需要自定义配置  
const MiniCssExtractPlugin = require('mini-css-extract-plugin');  
  
module.exports = {  
  optimization: {  
    minimize: true,  
    minimizer: [new TerserPlugin(/* options */)], // 如果需要自定义配置  
  },  
  module: {  
    rules: [  
      {  
        test: /\.css$/,  
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'] // 使用cssnano需要在postcss-loader中配置  
      }  
    ]  
  },  
  plugins: [  
    new MiniCssExtractPlugin({  
      filename: '[name].css',  
      chunkFilename: '[id].css',  
    }),  
  ],  
};

 5.压缩Node.js内存

不是Webpack配置,但相关

这不是Webpack的直接配置,但你可以通过调整Node.js的内存限制来影响Webpack的性能。这通常通过在命令行中设置--max-old-space-size参数来完成,不需要额外下载包。

node --max-old-space-size=4096 ./node_modules/.bin/webpack --config webpack.config.js

6.代码压缩

JS 压缩

webpack 4.0默认在生产环境的时候是支持代码压缩的,即mode=production模式下。实际上webpack 4.0默认是使用terser-webpack-plugin这个压缩插件,在此之前是使用 uglifyjs-webpack-plugin,两者的区别是后者对 ES6 的压缩不是很好,同时我们可以开启 parallel参数,使用多进程压缩,加快压缩。

CSS 压缩

CSS 压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等。可以使用另外一个插件:css-minimizer-webpack-plugin。

HTML 压缩

使用HtmlWebpackPlugin插件来生成 HTML 的模板时候,通过配置属性minify进行 html 优化。

module.exports = {
plugin:[
  new HtmlwebpackPlugin({
    minify:{
      minifyCSS: false, // 是否压缩css
      collapseWhitespace: false, // 是否折叠空格
      removeComments: true // 是否移除注释
    }
  })
  ]
}

7. 图片压缩

配置image-webpack-loader

8. Tree Shaking

Tree Shaking是一个术语,在计算机中表示消除死代码,依赖于 ES Module 的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系)。在webpack实现Tree shaking有两种方案:

usedExports:通过标记某些函数是否被使用,之后通过 Terser 来进行优化的

module.exports = {
    ...
    optimization:{
        usedExports
    }
  }

使用之后,没被用上的代码在webpack打包中会加入unused harmony export mul注释,用来告知Terser在优化时,可以删除掉这段代码。

sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用

sideEffects用于告知webpack compiler哪些模块时有副作用,配置方法是在package.json中设置sideEffects属性。如果sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports。如果有些文件需要保留,可以设置为数组的形式,如:

"sideEffecis":[
    "./src/util/format.js",
    "*.css" // 所有的css文件
]

9. 缩小打包域

排除webpack不需要解析的模块,即在使用loader的时候,在尽量少的模块中去使用。可以借助 include和exclude这两个参数,规定loader只在那些模块应用和在哪些模块不应用。

10. 减少 ES6 转为 ES5 的冗余代码

使用、bable-plugin-transform-runtime插件

11. 提取公共代码

通过配置CommonsChunkPlugin插件,将多个页面的公共代码抽离成单独的文件

12. 其他

组件懒加载、路由懒加载、开启gzip、公共的第三方包上cdn、配置cache缓存Loader对文件的编译副本、配置resolve提高文件的搜索速度(@: src)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值