Skip to content

构建工具

Webpack

  1. Webpack 是什么?它的核心功能是什么?

    • Webpack 是模块化打包工具,将分散的 JS、CSS、图片等资源视为模块,分析依赖关系并打包成静态文件。
    • 核心功能:代码编译、依赖分析、代码分割、资源优化。
  2. Webpack 的核心概念是什么?

    • 入口(Entry):指示 Webpack 应该从哪个文件开始构建依赖图(可以指定一个或多个入口文件)。
    • 输出(Output):指示 Webpack 在哪里输出打包文件。
    • 加载器(Loader):允许 Webpack 处理非 JavaScript 文件(如 CSS、图片、字体等)。
    • 插件(Plugin):用于扩展 Webpack 功能(如:优化资源、压缩代码、添加环境变量等)。
    • 模式(Mode):用于指定 Webpack 的构建模式,可以是开发模式(development)、生产模式(production)或其他。
  3. Loader 和 Plugin 的作用及区别是什么?

    • Loader:处理非 JS 文件(如转换 SASS/LESS 为 CSS、转换 ES6/ES7 为 ES5 等),按顺序链式调用。
    • Plugin:扩展 Webpack 功能(如生成 HTML 文件,代码压缩、资源优化、环境变量注入等),通过钩子影响打包全流程。

    记忆点:Loader 处理非 JS 文件,Plugin 扩展 Webpack 功能。

  4. Webpack 如何实现代码分割(Code Splitting)?

    • 入口分割:配置多入口(entry: { a: 'a.js', b: 'b.js' })。
    • 动态导入:使用 import() 语法,生成独立 chunk。
    • 配置 optimization.splitChunks 提取公共代码。

    记忆点:多入口 + 动态导入 + splitChunks 优化。

  5. Webpack 的 Tree Shaking 如何生效?需要满足哪些条件?

    • 基于 ES Module 静态语法(import/export),删除未使用代码。
    • 条件:生产模式(mode: 'production')、禁用 Babel 的 ESM 转换、package.json 中标记 sideEffects: false

    记忆点:ESM 语法 + 生产模式 + sideEffects 标记。

  6. Webpack 构建性能优化有哪些常见手段?

    • Tree Shaking: 使用 ES6 模块语法并启用 Tree Shaking 来消除未使用的代码,减小打包体积。
    • 代码拆分 (Code Splitting): 将应用程序拆分为多个 bundle,并实现按需加载,以减少初始加载时需要下载的资源量,加快页面加载速度。
    • 使用 CDN: 将第三方依赖库(如 React、Vue、jQuery 等)从打包中移除,并通过 CDN 引入,减小打包体积并加速页面加载。
    • 压缩资源: 使用 Webpack 的压缩插件(如 uglifyjs-webpack-plugin、terser-webpack-plugin 等)来压缩 JavaScript、CSS 代码等,减小文件体积。
    • 优化图片: 使用 image-webpack-loader 或者 url-loader 来优化图片资源,压缩图片并将小图片转换为 base64 格式,减少 HTTP 请求并加快加载速度。
    • 提取公共代码: 使用 Webpack 的 SplitChunksPlugin 来提取公共模块,减少重复代码,并将其打包到单独的文件中,以便浏览器缓存和复用。
    • 缓存优化: 使用 Webpack 的持久化缓存(persistent caching)功能,利用构建结果的 hash 值来标识构建结果的变化,从而提高构建效率。
    • 多进程构建: 使用 webpack-parallel-uglify-plugin、thread-loader 等插件来启用多进程构建,利用多核 CPU 提高构建速度。
    • 减少不必要的 Loader: 只加载必要的 Loader,避免加载过多的 Loader,以减少构建时间。
    • 使用 DllPlugin: 使用 webpack.DllPlugin 来预先编译第三方库,以减少每次构建时的依赖分析时间。
    • 减少文件搜索范围: 使用 resolve.modules、resolve.extensions、resolve.alias 等配置来减少文件搜索范围,提高构建速度。

Vite

  1. Vite 是什么?它解决了什么问题?

    • Vite 是新一代前端构建工具,解决传统打包工具(如 Webpack)开发环境冷启动慢热更新效率低的问题。
    • 核心思想:开发环境基于浏览器原生 ESM,生产环境用 Rollup 打包(最新版本使用 Rolldown 打包)。
  2. Vite 为什么开发环境比 Webpack 快?

    • 无打包:浏览器直接加载 ESM 模块。
    • 按需编译:只编译在浏览器中实际使用的代码。
    • 预构建:用 esbuild 将 CommonJS 依赖转换为 ESM。
    • 并行构建:多个进程中同时编译代码。
    • 缓存:依赖预构建结果缓存,避免重复编译。

    记忆点:原生 ESM + esbuild 预构建 + 缓存机制。

  3. Vite 的热更新(HMR)为什么高效?

    • 基于浏览器原生 ESM,仅更新修改的模块,无需重新构建依赖图。
    • 服务端通过 WebSocket 推送更新信息,客户端精准替换模块。

    记忆点:精准模块替换 + WebSocket 推送。

  4. Vite 如何处理 TypeScript 和 CSS 预处理器?

    • TypeScript:内置支持,直接编译(无需额外配置)。
    • CSS 预处理器:安装对应工具(如 sass/less/stylus)即可直接使用。

    记忆点:TS 开箱即用,CSS 预处理需安装工具。

  5. Vite 生产环境打包为什么选择 Rollup?

    • Rollup 的 Tree Shaking 更彻底,输出代码更小。
    • 更适合生成符合 ESM 标准的库或应用。

    记忆点:Rollup 更小的输出 + 更严格的 ESM 支持。

Rollup

  1. Rollup 是什么?它的设计目标是什么?

    • Rollup 是专注于 JavaScript 库打包的工具,设计目标是生成更小、更高效的代码,尤其适合库的发布。
      核心优势:Tree Shaking 彻底、输出格式灵活(ESM/UMD 等)。
  2. Rollup 和 Webpack 的主要区别是什么?

    • Rollup:适合库,输出扁平化代码,Tree Shaking 更彻底。
    • Webpack:适合应用,支持代码分割、动态加载等复杂功能。
  3. Rollup 如何处理 CommonJS 模块?

    • 需安装 @rollup/plugin-commonjs 插件转换 CommonJS 为 ESM。
    • 配合 @rollup/plugin-node-resolve 解析 node_modules 依赖。

    记忆点:CommonJS 需插件转换,Node 模块需解析插件。

  4. 为什么 Rollup 的 Tree Shaking 更高效?

    • 基于 ESM 静态分析,删除所有未使用的代码。
    • 输出结果无 Webpack 的模块包装代码,结构更扁平。

    记忆点:ESM 静态分析 + 无冗余代码。

  5. Rollup 如何实现代码分割(Code Splitting)?

    • 配置 output.dir 代替 output.file,输出多文件。
    • 使用动态导入(import())自动分割代码。

    记忆点:多文件输出 + 动态导入自动分割。

Rolldown

  1. Rolldown 是什么?它与 Rollup 和 Webpack 的主要区别是什么?

    Rolldown 是一个用 Rust 编写的新型 JavaScript 模块打包器,它兼容 Rollup 的 API 和配置格式。

    主要区别在于:Rolldown 通过 Rust 实现获得更高的构建性能;设计目标是成为 Vite 未来的打包基石,相比 Webpack 配置更简洁,比 Rollup 速度更快。

  2. Rolldown 在性能上有哪些优势?这些优势是如何实现的?

    Rolldown 的性能优势主要体现在更快的构建速度。这得益于其底层的 Rust 实现,以及高效的并行处理能力。Rolldown 在模块分析、树摇 (Tree-shaking) 和代码生成等环节进行了性能优化。

  3. 如何在现有项目中初步配置和使用 Rolldown?

    安装 Rolldown 后,创建一个 rolldown.config.js 文件。配置需要定义入口点 (input) 和输出选项 (output),其格式与 Rollup 配置文件相似。例如:

    javascript
    // rolldown.config.js
    export default {
      input: 'src/index.js',
      output: {
        file: 'dist/bundle.js',
        format: 'esm'
      }
    };
  4. Rolldown 的核心概念有哪些?

    Rolldown 的核心概念继承自 Rollup,主要包括:

    • Input (入口):指定打包的起始文件。
    • Output (输出):定义打包后文件的位置和格式 (如 ES module, CommonJS)。
    • Plugins (插件):用于在打包过程的不同阶段执行自定义任务,扩展功能。
    • Tree-shaking:静态分析代码,移除未被使用的导出,以减小最终包体积。
  5. 谈谈 Rolldown 的插件系统。如何编写一个自定义插件?

    Rolldown 的插件系统与 Rollup 兼容。一个插件就是一个对象,它通过实现特定的 钩子函数 (Hook) 来在打包生命周期 (如 buildStart, transform, generateBundle) 中注入自定义逻辑。例如,一个简单的插件可以在 transform 钩子中处理代码:

    javascript
    const myPlugin = () => {
      return {
        name: 'my-plugin',
        transform(code, id) {
          // 在这里转换代码
          return code;
        }
      };
    };

Babel

  1. Babel 是什么?它的工作原理是什么?

    Babel 是一个 JavaScript 编译器,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

    工作原理可以简单概括为三个步骤:解析(Parse)转换(Transform)生成(Generate)。解析步骤将代码转换成抽象语法树(AST),转换步骤对 AST 进行遍历并执行各种变换操作,生成步骤将变换后的 AST 再转换成代码字符串。

  2. Babel 的工作原理是什么?请描述其编译流程

    Babel 的编译分为三个核心阶段:

    • 解析 (Parsing):将源代码通过词法分析和语法分析转换为抽象语法树 (AST)
    • 转换 (Transforming):遍历 AST,应用插件对语法节点进行转换、增删改
    • 生成 (Code Generation):将转换后的 AST 重新生成为目标代码
  3. Babel 插件和预设 (Preset) 有什么区别?执行顺序是怎样的?

    • 插件:单个语法转换功能,如 @babel/plugin-transform-arrow-functions
    • 预设:插件集合,如 @babel/preset-env@babel/preset-react
    • 执行顺序:插件在预设前执行,插件从前往后,预设从后往前
  4. @babel/preset-env 的作用是什么?如何配置浏览器兼容性?

    • 作用:根据目标环境自动确定需要的转换和 polyfill
    • 配置方式
    javascript
    {
      "presets": [
        ["@babel/preset-env", {
          "targets": {
            "browsers": ["last 2 versions", "ie >= 11"]
          },
          "useBuiltIns": "usage", // 按需引入 polyfill
          "corejs": 3
        }]
      ]
    }
  5. Babel 的 polyfill 与 runtime 有什么区别?如何选择?

    • @babel/polyfill:全局引入,会污染全局环境,包含所有 ES6+特性
    • @babel/runtime:按需引入,局部变量,适合库开发
    • 选择:应用开发可用 polyfill,库开发推荐 runtime

AST

  1. 什么是 AST?它在编程语言处理中起什么作用?

    AST(抽象语法树)是源代码的结构化表示,它抽象掉代码的具体语法细节(如分号、括号),保留程序的结构和语义。主要作用:

    • 代码分析:ESLint、类型检查
    • 代码转换:Babel、代码压缩
    • 代码生成:编译器后端、代码格式化
  2. 描述从源代码到 AST 的完整解析过程

    解析过程分为两个关键阶段:

    javascript
    // 源代码:const sum = (a, b) => a + b
    
    // 1. 词法分析 (Lexical Analysis)
    // 输出 tokens: [const, sum, =, (, a, ,, b, ), =>, a, +, b]
    
    // 2. 语法分析 (Syntax Analysis)  
    // 构建 AST 结构:
    // VariableDeclaration
    //   - Identifier: sum
    //   - ArrowFunctionExpression
    //     - Parameters: [a, b]
    //     - Body: BinaryExpression (a + b)
  3. 在 JavaScript 生态中,AST 有哪些具体应用场景?

    主要应用场景:

    • Babel:ES6+ 代码转换,JSX 编译
    • ESLint/Prettier:代码规范检查和格式化
    • Webpack:模块依赖分析,Tree Shaking
    • TypeScript:类型检查,代码转换
    • 代码压缩工具:UglifyJS、Terser
  4. 如何通过工具操作和遍历 AST?请举例说明

    常用工具和模式:

    javascript
    // 使用 @babel/parser 解析
    const parser = require('@babel/parser');
    const ast = parser.parse('const x = 1;');
    
    // 使用 @babel/traverse 遍历和修改
    const traverse = require('@babel/traverse').default;
    traverse(ast, {
      Identifier(path) {
        if (path.node.name === 'x') {
          path.node.name = 'y'; // 重命名变量
        }
      }
    });
  5. 编写 Babel 插件时,AST 节点的 path 对象包含哪些重要信息?

    path 对象是关键 API,包含:

    • node:当前 AST 节点
    • parent:父节点引用
    • parentPath:父节点的 path 对象
    • scope:作用域信息(变量绑定)
    • context:转换上下文
    • 操作方法:replaceWith、remove、insertBefore 等

Gulp

  1. Gulp 是什么?它适用于什么场景?

    • Gulp 是基于流的自动化任务运行器,适用于文件转换、压缩、打包等重复性任务。
    • 典型场景:静态资源处理(如压缩图片、编译 SASS)。
  2. Gulp 的流(Stream)处理机制是什么?

    • 通过 gulp.src() 读取文件生成 Vinyl 虚拟文件流。
    • 使用 pipe() 连接插件处理文件(如 gulp-sass 编译 CSS)。
    • 最终通过 gulp.dest() 输出到磁盘。

    记忆点:src → pipe 处理链 → dest 输出。

  3. 如何用 Gulp 监听文件变化并自动执行任务?

    • 使用 gulp.watch() 监听文件变化。
    • 示例:gulp.watch('src/*.scss', gulp.series('compile-sass'))
  4. Gulp 如何处理任务间的依赖关系?

    • 使用 gulp.series() 按顺序执行任务(如先清理再构建)。
    • 使用 gulp.parallel() 并行执行任务(如同时压缩 JS 和 CSS)。

    记忆点:series 串行,parallel 并行。

Tree Shaking

  1. Tree Shaking 是什么?它的设计目标是什么?

    • Tree Shaking 是消除 JavaScript 中未使用代码的优化技术,通过静态分析模块依赖关系,删除未被引用的代码(“死代码”)。
    • 目标:减少代码体积,提升执行效率。

    记忆点:静态分析依赖,删除无用代码。

  2. Tree Shaking 的实现原理是什么?

    • 依赖 ES Module:利用 import/export 的静态语法特性(编译时分析依赖)。
    • 标记未引用代码:构建工具(如 Webpack/Rollup)标记未被使用的导出。
    • 删除阶段:在压缩阶段(如 Terser)移除标记的代码。

    记忆点:ESM 静态分析 → 标记 → 压缩删除。

  3. 如何确保 Tree Shaking 生效?需要满足哪些条件?

    • 代码层面:使用 ES Module(import/export),避免 CommonJS。
    • 工具配置
      • Webpack:mode: 'production'optimization.usedExports: true
      • Rollup:默认开启,无需额外配置。
    • 库标记:在 package.json 中设置 sideEffects: false(或指定副作用文件)。

    记忆点:ESM 语法 + 生产模式 + sideEffects 标记。

Released under the AGPL-3.0 License