⚠️温馨提示: 文档中包含【1个】暂不支持的区域,请通过搜索关键字【暂不支持的文档区域】进行后续处理

compiler-notes.zip

很多同学可能第一次来,我分享了很多干货公开课,希望对你的技术成长有帮助!免费分享都在这里,需要 文档和配套视频找咨询老师 领取~

【飞书文档】备战金九银十,进阶大前端,涨薪全突破! 跳槽涨薪需求同学必看

【飞书文档】项目没有难点亮点?字节大佬带你前端项目弯道超车

【飞书文档】字节大佬带你弯道超车,深入剖析大厂面试真题~

【飞书文档】面试被算法干吐了?字节大佬带你突破极限,冲击 30K+ 必掌握算法与 WebAssembly 技术 冲刺年包 50W+ 同学必看


【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节【超详细内培版】

【飞书文档】高级前端专家如何做项目架构与工程化设计? 特邀字节大佬细数字节开源项目架构细节【超详细内培版】

【飞书文档】小小微前端,轻松拿捏,特邀字节大佬开讲微前端架构与源码剖析【内部培训版】 35K+ 同学必看

【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节(二)【内部培训版】


【飞书文档】前端破局 AI 应用开发,特邀字节大佬分享字节系 AI 场景落地应用与 AI 引擎编排流程 探索前端新方向同学福音

【飞书文档】React18 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题

【飞书文档】Vue3 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题

【飞书文档】Vite 构建过程与源码深度剖析,你怎么也想不到一线大厂工程化构建面试会问这么深!

【飞书文档】脚手架/CLI 工具原理与开发实践,特邀字节前端专家带你体悟大厂团队基建与研发工作流 团队基建必看

【飞书文档】Webpack 原理深度解读与面试专项突击,字节面试官带你手撕难缠打包构建面试原理题 工程化与构建原理深入


【飞书文档】冲击中大厂筹备与涨薪突击最优方案,特邀字节面试官带你体验大厂面试全流程

【飞书文档】字节面试专场——中厂在职学员冲击大厂 30K+,看看面试官如何评价 大厂模拟面试,问得很深慎看

【飞书文档】前端性能与异常监控平台全链路设计与实践,字节架构师:掌握这整套拿个 40K+ 不在话下吧

【飞书文档】飞书文档协同编辑器技术揭秘,特邀字节架构师分享富文本编辑器方案细节

【飞书文档】大数据可视化引擎与数字孪生平台设计浅析,字节架构师:一起来剖析 DataWind 数据洞察平台架构之道


【飞书文档】服务端渲染(SSR)与前后端同构技术原理揭秘,字节前端专家带你光速进阶全栈 进阶必学

  1. Babel 使用与编译过程
  2. 编译原理
  3. 编译器手写实现公式字段计算
  • 初中级 】Babel 有了解过吗,请说说 Babel 的基础使用和原理?
  • 中高级 】有没有了解过编译原理,了解过编译器的底层实现吗?
  • 专家级 】从零到一架构实现一个类似飞书表格公式字段编译执行器,请简要说说你的设计思路

初中级 】Babel 有了解过吗,请说说 Babel 的基础使用和原理?

Babel 是一个广泛使用的 JavaScript 编译器,它的主要用途是将 ES6+ 等更新版本的 JavaScript 代码转换为 ES5 或者更低版本的代码,从而确保代码可以在更多的浏览器和环境中运行。Babel 的强大之处在于它的插件和预设(presets)机制,通过配置不同的插件,开发者可以有针对性地处理某些语法特性。

Babel 可以根据项目的需要选择性地进行语法转换,比如将箭头函数转换成普通函数、将新的语法糖转译成老版本支持的语法等。

Babel 的基础使用

项目结构及示例代码

为了说明 Babel 的基础使用,我们以一个简单的项目为例。该项目使用箭头函数的语法,但目标环境不支持,因此我们使用 Babel 将箭头函数转换为普通函数。

目录结构如下:

babel-demo/
├── dist/               # 编译后的输出文件
├── src/                # 源代码
│   └── index.js        # 源代码文件
├── babel.config.js     # Babel 配置文件
├── package.json        # 项目配置文件
└── node_modules/       # 依赖文件夹

package.json 文件

{
  "name": "babel-demo",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "build": "babel src --out-dir dist"
  },
  "keywords": [],
  "author": "Heyi",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@babel/core": "^7.25.7",
    "@babel/plugin-transform-arrow-functions": "^7.25.7",
    "@babel/preset-env": "^7.25.7",
    "@babel/cli": "^7.25.7"
  }
}

package.json 中,我们定义了一个 build 脚本,命令是 babel src --out-dir dist ,表示 Babel 将对 src 目录中的文件进行编译,并将结果输出到 dist 目录中。

devDependencies 中列出了我们需要的依赖项,包括 Babel 核心库、CLI 工具、插件和预设。

babel.config.js 文件

module.exports = {
  plugins: ["@babel/plugin-transform-arrow-functions"],
};

在 Babel 配置文件中,我们指定了使用 @babel/plugin-transform-arrow-functions 插件,它的作用是将箭头函数转换为普通的函数表达式。

虽然常见的 @babel/preset-env 预设可以处理各种语法转换,但为了演示插件机制,我们在这里只使用了单一的插件来处理箭头函数的转换。

src/index.js 文件

const sayHello = () => {
  console.log("妙码");
};

这个文件使用了 ES6 的箭头函数语法,目的是展示如何通过 Babel 将其转换为 ES5 语法。

运行 Babel 进行转换

在项目的根目录下,运行以下命令来安装依赖:

pnpm install

安装完成后,可以使用如下命令来运行 Babel 进行编译:

pnpm build

此时,Babel 会读取 src/index.js 文件,并根据 babel.config.js 的配置将箭头函数转换为普通函数,生成的文件会输出到 dist/index.js 文件中。

编译后的代码

编译后的代码 dist/index.js 会是如下形式:

const sayHello = function () {
  console.log("妙码");
};

可以看到,箭头函数 () => {} 被转换成了传统的匿名函数 function () {}

Babel 原理

Babel 的插件与预设

Babel 本身只是一个编译器,它不会自动转译代码,转译的工作是由插件和预设完成的。每个 Babel 插件负责处理特定的语法或语言特性,比如箭头函数、模板字符串、解构赋值等。

  • 插件(Plugins) :用于处理特定的语法转换,如 @babel/plugin-transform-arrow-functions 只处理箭头函数的转换。
  • 预设(Presets) :预设是一组插件的集合,比如 @babel/preset-env 是一个非常常用的预设,它包含了许多插件,可以将现代的 JavaScript 语法转译为目标环境支持的语法。

在我们的示例中,我们仅使用了 @babel/plugin-transform-arrow-functions 插件,因此 Babel 只会处理箭头函数的转换。

转换过程

Babel 的代码转换过程可以分为三个阶段:

  • 解析(Parsing) :Babel 首先将代码解析成抽象语法树(AST),这个过程类似于浏览器的 JavaScript 引擎解析代码的方式。
  • 转换(Transformation) :根据插件和预设的配置,Babel 会对 AST 进行遍历并修改,将不兼容的语法转换为兼容的语法。
  • 生成(Generation) :最终,Babel 将修改后的 AST 重新生成为 JavaScript 代码。

以箭头函数的转换为例,Babel 首先识别出箭头函数的语法节点,然后通过插件将其转换为等价的普通函数表达式,最后输出转换后的代码。

Babel 和 Polyfill

需要注意的是,Babel 只能转译语法,它不会为新 API 提供 Polyfill。例如,ES6 的 PromiseMap 等 API 无法通过 Babel 转换。如果需要支持这些 API,需要配合 core-jsregenerator-runtime 等库来实现 Polyfill。

拓展

当下,babel 依然不是最受欢迎的前端编译器,目前市面上还有很多比 babel 性能更好的编译器,比如:

  • Esbuild
  • swc
  • oxc

我们可以选择更合适的编译器进行模块编译,这里需要提示一下,在大厂,前端工具链的重构也是一个不错的方向,例如 go 语言写的 esbuild 性能得到了很大提升,再例如基于 rust 的 swc 性能更胜一筹,这些是由底层实现语言特性决定的。

中高级 】有没有了解过编译原理,了解过编译器的底层实现吗?

编译原理是计算机科学中的一个重要领域,主要研究如何将高级编程语言的源代码转换为机器能理解的目标代码(通常是二进制代码或中间代码)。编译器的底层实现通常包含多个阶段,包括词法分析、语法分析、语义分析和代码生成。我们将通过详细说明这些阶段,并提供代码示例和流程图来帮助理解编译器的工作原理。

编译的使用场景非常多,比如:

  • 前端资源构建与编译
  • 多端框架编译时处理
  • 飞书表格公式运行时编译&执行器实现

编译过程概述

编译过程分为以下几个步骤:

  1. 词法分析 :将源代码 let x = 10 + 20 分析为词法单元(Token)。
  2. 语法分析 :根据词法单元构建出抽象语法树(AST)。
  3. 语义分析 :检查语义,确认变量声明和作用域,确保代码逻辑的正确性。
  4. 代码生成 :将 AST 转换为目标代码,将 let 转换为 var

词法分析(Lexical Analysis)

词法分析是编译器的第一个阶段,它负责将源代码转换为 词法单元流 (Token Stream)。每个词法单元(Token)表示源代码中的一个最小元素,例如变量名、关键字、操作符、数字等。词法分析器会根据语言的定义来识别这些词法单元。

以下是一个简单的 JavaScript 词法分析器(lexer)的实现,它将源代码转换为词法单元流。

const TOKEN_TYPES = {
  KEYWORD: 'KEYWORD',
  IDENTIFIER: 'IDENTIFIER',
  OPERATOR: 'OPERATOR',
  NUMBER: 'NUMBER'
};

// 词法分析器
function lexer(input) {
  let tokens = [];
  let i = 0;

  while (i < input.length) {
    const char = input[i];

    // 匹配关键字 'let'
    if (char === 'l' && input.slice(i, i + 3) === 'let') {
      tokens.push({ type: TOKEN_TYPES.KEYWORD, value: 'let' });
      i += 3;
      continue;
    }

    // 匹配标识符 (变量名)
    if (/[a-zA-Z_]/.test(char)) {
      let identifier = '';
      while (i < input.length && /[a-zA-Z_]/.test(input[i])) {
        identifier += input[i];
        i++;
      }
      tokens.push({ type: TOKEN_TYPES.IDENTIFIER, value: identifier });
      continue;
    }

    // 匹配操作符和等号
    if (/[=+\-*\/]/.test(char)) {
      tokens.push({ type: TOKEN_TYPES.OPERATOR, value: char });
      i++;
      continue;
    }

    // 匹配数字
    if (/\d/.test(char)) {
      let num = '';
      while (i < input.length && /\d/.test(input[i])) {
        num += input[i];
        i++;
      }
      tokens.push({ type: TOKEN_TYPES.NUMBER, value: num });
      continue;
    }

    // 忽略空白字符
    i++;
  }

  return tokens;
}

// 测试
const sourceCode = 'let x = 10 + 20';
const tokens = lexer(sourceCode);
console.log(tokens);

对于输入 "let x = 10 + 20" ,词法分析器将输出如下的词法单元流:

[
  { "type": "IDENTIFIER", "value": "let" },
  { "type": "IDENTIFIER", "value": "x" },
  { "type": "OPERATOR", "value": "=" },
  { "type": "NUMBER", "value": "10" },
  { "type": "OPERATOR", "value": "+" },
  { "type": "NUMBER", "value": "20" }
]

语法分析(Parsing)

语法分析的任务是将词法单元流转换成 抽象语法树 (AST)。抽象语法树是编译器的核心数据结构,它以树的形式表达了代码的结构。语法分析器会根据语言的语法规则解析词法单元流,并构建出符合语言规范的 AST。

以下是一个简单的语法分析器,它将词法单元流转换为 AST。

const AST_NODE_TYPES = {
  VARIABLE_DECLARATION: 'VariableDeclaration',
  BINARY_EXPRESSION: 'BinaryExpression',
  IDENTIFIER: 'Identifier',
  LITERAL: 'Literal'
};

// 语法分析器
function parser(tokens) {
  let i = 0;

  function parseVariableDeclaration() {
    const token = tokens[i];
    if (token.type === TOKEN_TYPES.KEYWORD && token.value === 'let') {
      i++;
      const identifier = tokens[i];
      i++;
      const operator = tokens[i];
      i++;
      const expression = parseExpression();
      return {
        type: AST_NODE_TYPES.VARIABLE_DECLARATION,
        identifier: { type: AST_NODE_TYPES.IDENTIFIER, name: identifier.value },
        init: expression
      };
    }
  }

  function parseExpression() {
    let left = parsePrimary();

    while (i < tokens.length && tokens[i].type === TOKEN_TYPES.OPERATOR) {
      const operator = tokens[i].value;
      i++;
      const right = parsePrimary();
      left = {
        type: AST_NODE_TYPES.BINARY_EXPRESSION,
        operator,
        left,
        right
      };
    }

    return left;
  }

  function parsePrimary() {
    const token = tokens[i];
    if (token.type === TOKEN_TYPES.NUMBER) {
      i++;
      return { type: AST_NODE_TYPES.LITERAL, value: Number(token.value) };
    }
    if (token.type === TOKEN_TYPES.IDENTIFIER) {
      i++;
      return { type: AST_NODE_TYPES.IDENTIFIER, name: token.value };
    }
  }

  return parseVariableDeclaration();
}

// 测试
const ast = parser(tokens);
console.log(JSON.stringify(ast, null, 2));

语法分析器将生成以下 AST:

{
  "type": "VariableDeclaration",
  "identifier": {
    "type": "Identifier",
    "name": "x"
  },
  "init": {
    "type": "BinaryExpression",
    "operator": "+",
    "left": {
      "type": "Literal",
      "value": 10
    },
    "right": {
      "type": "Literal",
      "value": 20
    }
  }
}

语义分析(Semantic Analysis)

语义分析在 AST 的基础上进行,负责检查代码的正确性和安全性。例如,进行类型检查、作用域检查、变量声明的合法性等。语义分析确保代码不仅符合语法规则,还要保证程序在逻辑上是正确的。

以下是一个简单的语义分析器,它会检查变量是否已经声明,并抛出错误:

function semanticAnalysis(ast) {
  // 检查变量声明是否合法
  if (ast.type === AST_NODE_TYPES.VARIABLE_DECLARATION) {
    const varName = ast.identifier.name;
    if (varName === 'x') {
      console.log(`Variable '${varName}' is declared using let. Will be transformed to var.`);
    }
  }
}

// 语义分析阶段
semanticAnalysis(ast);

代码生成(Code Generation)

代码生成是编译器的最后一个阶段,它将经过语法和语义分析后的 AST 转换为目标代码。这个过程可以包括代码优化、生成中间代码(如字节码)、以及生成可执行的目标代码。

以下是一个简单的代码生成器,它将 AST 转换为 JavaScript 代码字符串:

function codeGeneration(node) {
  switch (node.type) {
    case AST_NODE_TYPES.VARIABLE_DECLARATION:
      return (
        'var ' +
        codeGeneration(node.identifier) +
        ' = ' +
        codeGeneration(node.init) +
        ';'
      );
    case AST_NODE_TYPES.BINARY_EXPRESSION:
      return (
        codeGeneration(node.left) +
        ' ' +
        node.operator +
        ' ' +
        codeGeneration(node.right)
      );
    case AST_NODE_TYPES.LITERAL:
      return node.value.toString();
    case AST_NODE_TYPES.IDENTIFIER:
      return node.name;
    default:
      throw new Error('Unknown node type: ' + node.type);
  }
}

// 生成目标代码
const generatedCode = codeGeneration(ast);
console.log(generatedCode);

编译器整体流程图

源代码
   ↓
词法分析器
   ↓
词法单元流(Tokens)
   ↓
语法分析器
   ↓
抽象语法树(AST)
   ↓
语义分析器
   ↓
经过检查的AST
   ↓
代码生成器
   ↓
目标代码

总结

编译器的底层实现通常包括词法分析、语法分析、语义分析和代码生成四个主要阶段。词法分析器将源代码转换为词法单元流,语法分析器将这些词法单元转换为抽象语法树,语义分析器在 AST 上执行类型检查和作用域检查,最后代码生成器将 AST 转换为目标代码。

专家级 】从零到一架构实现一个类似飞书表格公式字段编译执行器,请简要说说你的设计思路

在构建一个类似于飞书表格中公式字段的编译执行器时,我们需要从如何设计公式编辑器到公式的解析和执行这几个关键点进行详细的设计与实现。主要涉及以下几个方面:

  1. 公式编辑器的实现原理和功能。
  2. 编译执行器的架构,包括词法分析、语法分析、语义分析及执行过程。
  3. 使用 monaco-editor 实现语法高亮和编辑功能。

公式编辑器的实现原理

公式编辑器设计思路

在表格应用中,用户通常会编写类似 =SUM(A1:B2)=A1 + B1 * 2 这样的公式。公式编辑器需要具备以下功能:

  • 支持用户输入常见的算术操作(如加减乘除等)。
  • 支持函数调用(如 SUM()IF() )。
  • 实时反馈错误信息(如括号不匹配或未知函数)。
  • 提供自动补全、语法高亮功能,增强用户体验。

核心功能

  • Tokenize :将用户输入的公式拆分为词法单元(token)。
  • Parse :将词法单元解析为抽象语法树(AST),以便进一步分析和执行。
  • Interpret :遍历语法树,并结合上下文(表格中的数据)执行公式。
  • Error Handling :在编辑过程中实时检测语法或执行错误。

语法高亮和编辑功能

为提高用户体验,可以使用 monaco-editor ,它是一个强大的代码编辑器,提供自动补全、语法高亮等功能,特别适用于复杂的公式或表达式输入。

设计流程图

用户输入公式
    ↓
Monaco-Editor (语法高亮、自动补全)
    ↓
Tokenizer (词法分析器)
    ↓
Parser (语法分析器)
    ↓
AST (抽象语法树)
    ↓
Interpreter (执行器)
    ↓
返回结果

实现过程:编译执行器

词法分析(Tokenizer)

首先,我们需要将用户输入的表达式分解为词法单元,例如变量、数字、函数和操作符。下面的 tokenize 函数负责这个步骤:

// Tokenizer: 将表达式拆解为词法单元
function tokenize(expression) {
  const tokens = [];
  let current = 0;

  while (current < expression.length) {
    let char = expression[current];

    // 处理数字
    if (/\d/.test(char)) {
      let number = '';
      while (/\d/.test(char)) {
        number += char;
        char = expression[++current];
      }
      tokens.push({ type: 'number', value: parseInt(number) });
      continue;
    }

    // 处理变量或函数
    if (/[a-zA-Z]/.test(char)) {
      let id = '';
      while (/[a-zA-Z]/.test(char)) {
        id += char;
        char = expression[++current];
      }

      // 跳过空格
      while (expression[current] === ' ') {
        current++;
      }

      // 如果下一个字符是 '(',则标记为函数
      if (expression[current] === '(') {
        tokens.push({ type: 'function', value: id });
      } else {
        tokens.push({ type: 'variable', value: id });
      }
      continue;
    }

    // 处理操作符或括号
    if (char === '(' || char === ')' || char === ',') {
      tokens.push({ type: char, value: char });
      current++;
      continue;
    }

    // 处理小数点
    if (char === '.') {
      tokens.push({ type: 'dot', value: '.' });
      current++;
      continue;
    }

    if (char === ' ') {
      current++;
      continue;
    }

    throw new TypeError('Unknown character: ' + char);
  }

  return tokens;
}

语法分析(Parser)

通过语法分析器,我们将词法单元转化为抽象语法树(AST)。在 AST 中,树的每个节点代表一个操作或操作数。

// Parser: 将词法单元解析为抽象语法树
function parse(tokens) {
  let current = 0;

  function walk() {
    let token = tokens[current];

    // 处理数字
    if (token.type === 'number') {
      current++;
      return { type: 'NumberLiteral', value: token.value };
    }

    // 处理函数调用
    if (token.type === 'function') {
      current++;
      const node = {
        type: 'CallExpression',
        name: token.value,
        params: []
      };
      token = tokens[++current]; // 跳过 '('

      while (token.type !== ')') {
        node.params.push(walk());
        token = tokens[current];
        if (token.type === ',') {
          current++; // 跳过 ','
        }
      }

      current++; // 跳过 ')'
      return node;
    }

    // 处理变量
    if (token.type === 'variable') {
      let value = token.value;
      current++;

      // 处理属性访问如 'person.age'
      while (tokens[current] && tokens[current].type === 'dot') {
        current++; // 跳过 '.'

        if (tokens[current] && tokens[current].type === 'variable') {
          value += '.' + tokens[current].value;
          current++;
        } else {
          throw new TypeError('Expected variable after "."');
        }
      }

      return { type: 'Variable', value };
    }

    throw new TypeError('Unknown token type: ' + token.type);
  }

  const ast = {
    type: 'Program',
    body: []
  };

  while (current < tokens.length) {
    ast.body.push(walk());
  }

  return ast;
}

解释器(Interpreter)

解释器负责遍历抽象语法树并执行操作。每个节点根据其类型(如 NumberLiteralCallExpressionVariable )进行相应的处理。

// Interpreter: 执行抽象语法树中的操作
function interpret(ast, context = {}) {
  const operators = {
    'Add': (a, b) => a + b,
    'Subtract': (a, b) => a - b,
    'Multiply': (a, b) => a * b,
    'Divide': (a, b) => a / b
  };

  function traverseNode(node) {
    if (node.type === 'NumberLiteral') {
      return node.value;
    }

    if (node.type === 'Variable') {
      const keys = node.value.split('.');
      let value = context;
      for (let key of keys) {
        if (!(key in value)) {
          throw new TypeError('Unknown variable: ' + key);
        }
        value = value[key];
      }
      return value;
    }

    if (node.type === 'CallExpression') {
      const args = node.params.map(traverseNode);
      const func = operators[node.name];
      if (!func) {
        throw new TypeError('Unknown function: ' + node.name);
      }
      return func(...args);
    }

    throw new TypeError('Unknown node type: ' + node.type);
  }

  return traverseNode(ast.body[0]);
}

使用示例

最后,结合上述代码,通过一个示例来展示整个流程,从输入公式到生成结果。

// 示例数据
const person = { age: 2 };
const expression = "Subtract(Add(3, Multiply(4, person.age)), Divide(6, person.age))";

// 执行整个流程
const tokens = tokenize(expression);
const ast = parse(tokens);
const result = interpret(ast, { person });

console.log(result); // 输出 8

编辑器支持:Monaco Editor

使用 monaco-editor 来实现公式的编辑、自动补全和语法高亮。 monaco-editor 是微软 VS Code 所使用的编辑器组件,可以为公式编辑器提供高效的开发体验。

import React, { useRef } from "react";
import Editor, { Monaco } from "@monaco-editor/react";

const customLanguage = {
  // 定义关键词和操作符
  keywords: ["Add", "Subtract", "Multiply", "Divide"],
  operators: ["+", "-", "*", "/"],
  symbols: /[=><!~?:&|+\-*\/^%]+/,

  tokenizer: {
    root: [
      // 数字
      [/\d+/, "number"],

      // 函数名
      [
        /[a-zA-Z_]\w*/,
        {
          cases: {
            "@keywords": "keyword",
            "@default": "identifier",
          },
        },
      ],

      // 操作符
      [/[{}()\[\]]/, "@brackets"],
      [
        /@symbols/,
        {
          cases: {
            "@operators": "operator",
            "@default": "",
          },
        },
      ],
    ],
  },
};

export function FormulaEditor() {
  const editorRef = useRef(null);

  const handleBeforeMount = (monaco: Monaco) => {
    const customCompletionProvider = {
      // 提供自动补全项
      provideCompletionItems: (model, position) => {
        const suggestions = [
            {
              label: "Add",
              kind: monaco.languages.CompletionItemKind.Function,
              insertText: "Add(${1:num1}, ${2:num2})",
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
              detail: "Add function",
              documentation: {
                value: "The `Add` function takes two arguments and returns their sum.",
                isTrusted: true // 确保文档内容被正确信任
              }
            },
            {
              label: "Subtract",
              kind: monaco.languages.CompletionItemKind.Function,
              insertText: "Subtract(${1:num1}, ${2:num2})",
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
              detail: "Subtract function",
              documentation: {
                value: "The `Subtract` function takes two arguments and subtracts the second from the first.",
                isTrusted: true
              }
            },
            {
              label: "Multiply",
              kind: monaco.languages.CompletionItemKind.Function,
              insertText: "Multiply(${1:num1}, ${2:num2})",
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
              detail: "Multiply function",
              documentation: {
                value: "The `Multiply` function takes two arguments and returns their product.",
                isTrusted: true
              }
            },
            {
              label: "Divide",
              kind: monaco.languages.CompletionItemKind.Function,
              insertText: "Divide(${1:num1}, ${2:num2})",
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
              detail: "Divide function",
              documentation: {
                value: "The `Divide` function takes two arguments and returns the result of dividing the first by the second.",
                isTrusted: true
              }
            }
          ];

        return { suggestions: suggestions };
      },
    };

    monaco.languages.register({ id: "formulaLang" });

    // 定义自定义的语法高亮规则
    monaco.languages.setMonarchTokensProvider("formulaLang", customLanguage);

    // 注册自动补全
    monaco.languages.registerCompletionItemProvider(
      "formulaLang",
      customCompletionProvider
    );
  };

  return (
    <div style={{ height: "500px", width: "800px" }}>
      <Editor
        height="100%"
        defaultLanguage="formulaLang"
        defaultValue="Subtract(Add(3, Multiply(4, person.age)), Divide(6, person.age))"
        beforeMount={handleBeforeMount}
        onMount={(editor) => (editorRef.current = editor)}
      />
    </div>
  );
}

简历优化(35K+ 简历模板)

技能描述

  • 熟练掌握 HTML、CSS、JavaScript、Typescript 以及 OOP、FP、 AOP 等设计思想

  • 掌握样式体系构建与落地,对 css 预编译、css in js、module css 以及 utility-first CSS 有深入研究,并从零改良过样式体系以支持 SSR、SSG

  • 熟悉 React、Vue 相关技术栈,熟悉 React、Vue 及相关技术框架的实现原理

  • 掌握构建工具 Webpack、Vite 等,掌握编译工具 Babel,并深入理解其原理,并参与 Rspack 构建

  • 丰富的数据可视化经验,熟悉 Canvas、svg 开发范式,理解 Echarts、Antv 原理,能根据业务需求基于 d3、zrender 开发自定义渲染引擎

  • 丰富的跨端开发经验,熟练使用 Taro、Flutter、React-Native 开发跨端应用,对构建 hybird App 有丰富经验,深入理解跨端开发编译原理

  • 基于 Node.js 开发脚手架、打包构建优化工具及中间件服务

  • 掌握常用设计模式、算法与安全知识,追求开发高质量、高可维护性代码,追求极致产品体验

  • 团队管理经验,并在项目架构设计与性能优化方面具有丰富经验

  • 算法与编程技术

    • 精通各种算法题的分类及解决方法,包括排序与查找、数据结构、动态规划、贪心算法、回溯算法、分治算法、图论算法、数学算法等。
    • 重点掌握动态规划的基本概念、解题步骤和经典题目。
  • 3D 数字孪生平台开发经验

    • 熟练使用 WebGL 和 WebAssembly 技术,开发高效的 3D 渲染引擎。
    • 精通正射影像和倾斜摄影技术,具备 Tile 和模型(包括白膜和精模)的处理经验,能够使用 Blender 进行模型制作。
    • 熟悉材质、光效和粒子系统的实现与优化。
  • 全面性能优化能力

    • 具备打包构建优化经验,熟练使用 Webpack 进行模块打包,掌握 chunk、treeshaking、happypack、cache-loader 等优化技巧,并使用 Webpack Module Federation 进行模块联邦管理。
    • 精通资源优化,能够有效进行图片、字体压缩,管理请求队列,并通过 OSS 和 CDN 提升资源加载速度。
    • 具有应用性能优化经验,包括数据结构优化和应用模块更新。
    • 深入了解缓存机制,熟悉强缓存(Expiration、Cache-Control)、协商缓存(Etag)和策略缓存(Service-Worker)的配置与管理。

项目描述

这个环节至关重要,很多同学不重视,简历随便写一写就开始投递了,结果投出去几百份可能一家公司面试都没有,结果就在怀疑前端行情出问题了

STAR 法则:

  • 遇到了什么问题 question,需求
  • 怎么评估解决方案,方案对比,方案落地 react 状态管理(redux、mobx、jotai、recoil)Vue3 -> Pinia
  • 具体方案落地
  • 结果反思,细节优化思考

大家先看这段描述:

技术栈:Java、Vue2、echarts、WEui、BaiduMap、JavaScript 、HTTP数据库:MySQL管理工具:SVN

责任描述:

1)产品前端研发负责人,主要负责整体样式沟通,样式调配实现;门户、管理平台、移动端、智端、可视化等前端内容实现;

2)实现组织管理、人员管理、党员关系转接、待办通知、绩效考核(复杂功能算法实现)、发展党员(25个流程)、可视化等主体功能,兼容性优化、适配1920*1080屏幕以及响应式布局实现;

3)相关功能开发,包含前后端、数据库;

4)门户框架搭建、门户整体设计、后端接口、门户前端 UI 实现等;

5)微信小程序框架搭建、小程序页面设计及开发、知识图谱技术预演;

6 )项目经理工作辅助,包含需求沟通、UI设计沟通、交付材料项目经历整理、前端代码质量管理、部分功能设计。

深度优化一下

工作内容和成果

  • 架构设计 】参与智慧管理平台整体架构设计、技术选型与方案评审,担任全栈开发,完成相关核心模块
  • 企微开发 】对接企业微信生态,基于企微 SDK 完成平台支付、消息推送、机器人等功能开发
  • 可视化 】主导完成平台可视化渲染引擎(可视化图表的组件,数据协议)设计与开发,基于 echarts (svgRenderer、canvasRenderer 一千万行数据的表格渲染【不能使用 虚拟滚动 】 canvas table,chunk)封装业务图表库,服务于平台可视化场景
  • 地图开发 】使用百度地图 SDK,封装业务地图渲染器(MapRenderer),包含:地图撒点、地区数据下钻等功能
  • 小程序与App 】基于 uniapp 实现智慧党建用户端多端开发落地,产物编译为 H5、微信小程序两端应用
  • 团队基建 】推进团队业务组件库、图表库与基础库沉淀,完成 10+ 个业务组件沉淀,以此提升了团队协同开发效率
  • 优化 】设计产品响应式系统,基于 media query 设计响应式端点规则,适配不同端应用的展示
  • 自研 OA 打通 】...

STAR

【技术栈】

  • Java、Vue2、ECharts、WEui、BaiduMap、JavaScript、HTTP
  • 数据库 :MySQL
  • 管理工具 :SVN

【产品前端研发负责人】

  • 情境 (Situation) :担任产品前端研发负责人,负责门户、管理平台、移动端、智端、可视化等前端内容的实现。
  • 任务 (Task) :主要任务是与设计团队沟通,调配和实现整体样式,确保产品界面的一致性和用户体验。
  • 行动 (Action) :我协调设计与开发团队,定期召开样式沟通会,亲自进行样式的调配与实现,并负责不同平台和设备的前端内容开发。
  • 结果 (Result) :成功实现了多个平台的前端开发工作,提升了产品的用户体验和一致性,获得了团队和用户的高度评价。

【实现复杂功能及优化】

  • 情境 (Situation) :项目需要实现复杂功能算法和大规模功能模块,包括组织管理、人员管理、党员关系转接、待办通知、绩效考核、发展党员(25个流程)和可视化功能。
  • 任务 (Task) :负责上述复杂功能的实现,并优化其兼容性和响应式布局。
  • 行动 (Action) :通过设计和实现复杂算法,确保各模块的功能性;进行兼容性优化,使系统适配1920*1080屏幕和响应式布局。
  • 结果 (Result) :成功实现并优化了所有复杂功能,系统在不同设备和分辨率下均表现良好,提高了用户操作的流畅度和满意度。

【全面功能开发】

  • 情境 (Situation) :需要进行前后端和数据库的全面开发,确保系统各功能模块的无缝集成。
  • 任务 (Task) :开发和实现相关功能,包括前端UI、后端接口和数据库交互。
  • 行动 (Action) :采用Java、Vue2等技术,开发并调试各功能模块,与后端团队密切合作,确保接口的准确性和数据的一致性。
  • 结果 (Result) :成功完成了所有功能模块的开发和集成,系统运行稳定,性能优异,受到了客户的好评。

【微信小程序开发与知识图谱预演】

  • 情境 (Situation) :项目需要开发微信小程序,并进行知识图谱技术的预演。
  • 任务 (Task) :负责小程序框架的搭建、页面设计及开发,同时进行知识图谱的技术预演。
  • 行动 (Action) :使用WEui、JavaScript等技术,设计并开发小程序页面,进行知识图谱的技术预演和验证。
  • 结果 (Result) :成功搭建了微信小程序框架,完成了页面设计和开发工作,知识图谱技术预演顺利,通过了技术验证。

【项目经理工作辅助】

  • 情境 (Situation) :在项目中辅助项目经理,确保项目需求沟通顺畅,UI设计协调到位,交付材料齐全,前端代码质量高。
  • 任务 (Task) :辅助项目经理进行需求沟通、UI设计沟通、交付材料整理、前端代码质量管理以及部分功能设计。
  • 行动 (Action) :积极参与需求和UI设计的沟通,整理和管理项目交付材料,进行代码审查和质量管理,并参与功能设计。
  • 结果 (Result) :成功辅助项目经理完成了项目的各项工作,提高了项目的开发效率和交付质量,确保了项目的顺利进行。

其实还不够,这些项目才是求职香饽饽

你可能不具备这些项目的实战经验,很多同学写了很多年管理系统,简单增删改查项目,如果不跳出这个圈子,很难在薪资上有非常大的突破!

  • 大厂 UI 组件库(Vue3)整体设计与开发实践(monorepo 架构)

  • 大厂业务 Hooks 库(React 18)整体设计与开发实践(从零到一的架构、规范流程)

  • 企业级脚手架工具开发实践

  • 企业级文档编辑器飞书文档开发实践

  • 前端性能、异常与行为监控

  • 3D 可视化数字孪生低代码实战 💥

    • 基于 cesium(arcGis、超图) 方案的 WebGIS 开发实践
    • 基于 openlayer、mapbox 开发
    • 基于 WebGL 3D 可视化开发实践

年包 50W+ 薪资长线规划

核心要素

  1. 全面的技术储备

    1. 框架基础

      • Vue 和 React 经验:包括 Vue3 + Typescript 和 React18(Hooks、Concurrent)
      • 掌握框架原理:React 生态库(React-Router、Redux)和 Vue 生态库原理
    2. 工程化能力

      • 构建工具:Webpack、Vite、Rspack、ESBuild、swc
      • CI/CD 自动化:自动化构建和自动化部署
    3. 基建能力

      • Node.js、命令行工具开发(Cli)
      • UI 库、图表库、工具库开发
    4. 业务领域经验

      • 管理系统和图表类应用
      • 可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
  2. 项目经验

    • 参与过至少两个大型项目,并主导过一个复杂项目
    1. 管理系统:包括项目搭建、技术方案选择、技术栈构建、CI/CD 流程
    2. 其他领域项目:如可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
  3. 面试表现

    1. 个人介绍

      • 准备个人介绍草稿,涵盖基本信息、技术栈和项目重难点
    2. STAR 法则

      • 问题描述:阐述遇到的问题或需求
      • 解决方案评估:方案对比与选择(如 React 状态管理:redux、mobx、jotai、recoil,Vue3 使用 Pinia)
      • 方案实施:具体的实施步骤
      • 反思与优化:项目反思及优化建议
    3. 面试准备

      • 重点复习知识点:如 v8 内存管理、Promise A+ 规范、事件循环、this、面向对象编程原型
      • 技术储备:结合项目经验展示技术在项目中的应用
  4. 学历提升

    1. 现有学历:大专
    2. 未来计划:尽快取得本科证书(不需要注明具体年限)
    3. 学历背景:民办学校
    4. 内推建议:应对学历和工作经历问题,通过内推提升机会

补足短板

  • 项目简单,管理后台一做就是大半年,天天 CRUD

    • 看开源项目(react-hook-form ts 类型、hook 处理、状态管理、架构 Provider,keyPath)
    • 找一些不错的项目练手
    • 拿好的项目,学习完放在简历里, 可视化、编辑器、云表格、低代码、SaaS 产品、数字孪生、三维可视化
    • 1.自研:15K, 2.外包:20K ,这个火坑, 灰(供需决定)
  • 技术栈掌握不深不广,只会用 Vue2 (Vue3 + Typescript),React18(React stack reconciler)

  • 架构、方案设计没碰过

    • React,create-react-app、umi,没有真正从零到一去设计初始化过一个项目
    • Vue,Vue CLI,Vite/Webpack。Vue2 CLI 创出来项目 1. webpack、2.vite
  • 没有专精的技能或业务

    • 自驱 (假定自己是 Leader),项目的赢利点、商业价值【 可视化、编辑器、白板、团队基建、AI产品
    • 与生俱来有些东西,好奇心、自驱力、清晰规划
    • 我:管理平台,HPE(官网、后台管理),云表格(维格表、飞书云表格)、云编辑器(CKEditor 老【html string】)(语雀、【石墨文档】)

妙码学院——全程陪跑、督学、内推

⚠️ 暂不支持的文档区域,【文档小组件】

  • 跨端开发 Taro(Taro 编译器 compiler、运行时 runtime)、uniapp
  • 协同编辑器(文档类、画板类)wangEditor、CKEditor
  • 团队基建工程(UI 库、图表库、Cli -> 产生产物 npm 包)
  • 3D 可视化数字孪生 bigdata
  • 低代码平台

课程体系 2.0 升级,除了基础知识夯实,融入了更多项目实战内容,包含:

  • 企业级脚手架工具开发实践

  • 企业级文档编辑器飞书文档开发实践

  • 大厂 UI 组件库(Vue3)整体设计与开发实践

  • 大厂业务 Hooks 库(React 18)整体设计与开发实践

  • 埋点与数据监控平台实战

  • 3D 可视化数字孪生实战 💥

    • 基于 cesium 方案的 WebGIS 开发实践
    • 基于 WebGL 3D 可视化开发实践

妙码学院全网独家项目实战矩阵

所有项目实战,均完全 从零到一手写纯原创 ,项目架构与编码规范真一线大厂级。

  • 微前端在分拆原子应用场景下的落地与实践

  • 协同编辑器从零到一架构实现

  • 推动团队基建落地

    • React UI 库
    • Vue Composition API 库
    • 企业级脚手架
  • 数字孪生平台整体架构设计

  • 企业级无代码可视化平台实践(Vue3)

  • 低代码平台设计与实现

    • 编排引擎
    • 流程引擎
    • 编辑器
    • 代码执行器与 JavaScript 沙箱
  • 用户行为分析 SDK 及监控可视化整体实现

  • 可视化渲染引擎设计与实现

  • 基于 RAG / Agent 前端 AI 应用流程编排平台

不同阶段对前端人的硬性要求

以下是对您提供的内容进行权威和专业化改写的建议:

1~3年

在此阶段,重点在于评估个人的基础知识和热情。对前端基础、计算机原理、网络通信和算法等领域的要求较高。由于在此阶段难以评估业务深度,因此更多关注基础知识的掌握程度。

  • 关键在于通过学术教育或网络资源加强基础知识;
  • 在简历中以多种方式展示对前端的热情,展现个人潜力;
  • 积极探索前沿技术,关注国内外技术动态;
  • 尝试开发小型项目或参与社区开源项目;
  • 建立技术博客,以输出促进知识吸收。

3~5年

此阶段通常是向成为独立工程师发展的关键时期,避免重复使用有限的经验。

  • 关注社区中关于进阶的资料和路线,强化基础知识;

  • 深入掌握常用框架的高级用法,探索其原理;

  • 在业务开发中不仅完成功能,还需考虑项目结构设计、封装基础工具、设计和开发基础组件;

  • 思考提高团队效率的方法,例如:

    • 集成代码检验和风格统一插件(如 eslint、stylelint、prettier、spellcheck);
    • 从工程化角度提高本地开发效率,优化webpack构建,探索esbuild、vite等工具;
    • 对于多项目开发,整理差异和统一部分,建立内部脚手架以减少重复工作;
    • 尝试搭建CI/CD平台,维护公司内部的通用npm包;
    • 培养软技能,如沟通协作,协调各角色共同推进目标。

5年以上

进入此阶段,可能朝技术专家或管理方向发展。期望您能够独立负责高复杂度项目,突破关键技术难题。

  • 负责技术调研,关注行业趋势,选择最优技术方案,具备决策能力;
  • 拥有丰富的技术经验和技术储备,能够解决遇到的困难,并有自己的方法论;
  • 协助或主导业务目标制定,合理推动项目达成预期效果;
  • 是否具有团队领导经验,能够协调跨团队项目,处理团队成员情绪问题,解决技能分布不平衡等问题;
  • 打造技术氛围,促进团队共同成长。

职业规划指导

评论区选取三位同学互动,其他同学也可以联系咨询老师,文字方式提供辅导解答。

【未知组件reminder】