⚠️温馨提示: 文档中包含【1个】暂不支持的区域,请通过搜索关键字【暂不支持的文档区域】进行后续处理
很多同学可能第一次来,我分享了很多干货公开课,希望对你的技术成长有帮助!免费分享都在这里,需要 文档和配套视频找咨询老师 领取~
【飞书文档】面试被算法干吐了?字节大佬带你突破极限,冲击 30K+ 必掌握算法与 WebAssembly 技术
【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节【超详细内培版】
【飞书文档】高级前端专家如何做项目架构与工程化设计? 特邀字节大佬细数字节开源项目架构细节【超详细内培版】
【飞书文档】小小微前端,轻松拿捏,特邀字节大佬开讲微前端架构与源码剖析【内部培训版】 35K+ 同学必看
【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节(二)【内部培训版】
【飞书文档】前端破局 AI 应用开发,特邀字节大佬分享字节系 AI 场景落地应用与 AI 引擎编排流程
【飞书文档】React18 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题
【飞书文档】Vue3 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题
交代问题的背景,或者是发展的历史
给出对应解决方案
具体方案落地
反思与优化
【 初中级 】面试官:请说说你对 Vite 的理解,什么是 bundleless 呢?
【 中高级 】面试官:Vite 构建过程了解吗,说说其实现原理?
【 专家级 】面试官:如果让你设计一个打包工具,你怎么设计?
【 初中级 】面试官:请说说你对 Vite 的理解,什么是 bundleless 呢? |
Vite 是一个新型的前端构建工具,它在开发和构建过程中都显著提高了效率。它的核心思想是“bundleless”,即在开发阶段不进行打包操作,而是利用浏览器的原生 ES 模块(ESM)支持来实现模块加载。
不过要想说到面试官心坎儿里去,还得按这个回答结构来,我总结好了,大家直接领取学习。
- 模块化规范演进 ,这就说明为啥 2015 年以前,文件满天飞,毫无工程化可言
- 浏览器 ESM :这就说明为啥 2015 年没有 bundleless,偏偏到 2020 年
- 本地开发处理 :本地开发只打包必须要打的内容,例如:commonjs 的内容、jsx、vue (esbuild 来打)等,并存入缓存
- 产物构建处理 :产物构建使用 rollup 进行构建
模块化的发展史及实现
发展史
- 初期阶段 : 最早的前端开发中,代码模块化几乎不存在,所有的代码都写在一个文件中,导致难以维护和扩展。
- CommonJS : 随着 Node.js 的流行,CommonJS 模块化规范被广泛应用,通过
require和module.exports实现模块加载和导出。 - AMD (Asynchronous Module Definition) : 为解决浏览器环境中模块异步加载的问题,RequireJS 推出了 AMD 规范,使用
define和require。 - ES6 Modules (ESM) : ES6 引入了原生的模块化支持,即 ESM,使用
import和export,并得到广泛支持。
各模块化具体实现与代码示例
- CommonJS :
// math.js
const add = (a, b) => a + b;
module.exports = { add };
// main.js
const { add } = require('./math');
console.log(add(2, 3)); // 5
- AMD :
// math.js
define([], function() {
return {
add: function(a, b) {
return a + b;
}
};
});
// main.js
require(['./math'], function(math) {
console.log(math.add(2, 3)); // 5
});
- ESM :
// math.js
export const add = (a, b) => a + b;
// main.js
import { add } from './math';
console.log(add(2, 3)); // 5
浏览器 ESM 支持
ESM(ECMAScript Modules)在现代浏览器中得到了广泛支持,使得前端开发可以直接利用 import 和 export 进行模块化开发,而无需借助打包工具。浏览器通过 <script type="module"> 标签来加载 ES 模块。Vite 正是利用了这一特性来实现无打包的开发模式。
Vite 本地开发 server 的实现
Vite 的本地开发 server 主要依赖以下几个核心机制:
- 原生 ESM 加载 : Vite 不对模块进行预打包,而是直接利用浏览器的 ESM 能力,通过 HTTP 请求动态加载模块。
- 按需编译 : 当浏览器请求某个模块时,Vite 会实时编译该模块并返回给浏览器,而非一次性打包所有模块。
- 热模块替换(HMR) : Vite 通过 WebSocket 实现 HMR,在模块更新时,仅重新编译并推送发生变化的模块到浏览器,极大提升了开发效率。
示例:
// server.js
import express from 'express';
import { createServer } from 'vite';
const app = express();
createServer({
server: { middlewareMode: 'ssr' }
}).then(vite => {
app.use(vite.middlewares);
app.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});
});
开发与构建分离
Vite 通过将开发和构建分离来提高效率:
- 开发模式 : 利用浏览器原生的 ESM 支持,模块按需加载,避免了传统打包工具在开发阶段频繁打包的性能瓶颈。
- 构建模式 : 在生产环境中,Vite 依然会使用 Rollup 对代码进行打包优化,生成高效的静态资源。构建时会进行代码拆分、Tree Shaking 等优化操作,以确保产出的代码尽可能小且高效。
开发模式的无打包特性和构建模式的优化结合,使 Vite 在开发和构建阶段都能提供极高的性能。
Vite 源码提要
const externalTypes = [
'css',
// supported pre-processor types
'less',
'sass',
'scss',
'styl',
'stylus',
'pcss',
'postcss',
// wasm
'wasm',
// known SFC types
'vue',
'svelte',
'marko',
'astro',
'imba',
// JSX/TSX may be configured to be compiled differently from how esbuild
// handles it by default, so exclude them as well
'jsx',
'tsx',
...KNOWN_ASSET_TYPES,
]
const depsOptimizer: DepsOptimizer = {
metadata,
registerMissingImport,
run: () => debouncedProcessing(0),
isOptimizedDepFile: createIsOptimizedDepFile(config),
isOptimizedDepUrl: createIsOptimizedDepUrl(config),
getOptimizedDepId: (depInfo: OptimizedDepInfo) =>
`${depInfo.file}?v=${depInfo.browserHash}`,
close,
options,
}
【 中高级 】面试官:Vite 构建过程了解吗,说说其实现原理? |
Vite 构建过程详述
要了解 Vite 构建过程,需要从两个主线展开:
- 本地开发
- 产物构建
Vite 本地开发服务(Vite Dev Server)
1. 项目初始化
当启动本地开发服务时(通过 vite 或 npm run dev 命令),Vite 会读取项目根目录下的 vite.config.js 配置文件,并进行项目初始化,包括设置别名、插件和代理等配置。
2. 启动开发服务器
Vite 使用一个基于 express 的开发服务器,在本地启动一个 HTTP 服务器,用于处理浏览器的请求。
3. ESM 支持
在开发模式下,Vite 利用浏览器的原生 ESM 支持,直接在浏览器中加载 ES 模块。Vite 会对每个模块的请求进行拦截,并根据模块类型进行处理:
- JavaScript 模块 : 直接通过
<script type="module">加载。 - CSS 文件 : 通过动态创建
<style>标签进行加载。 - 静态资源 : 根据请求的 URL 返回相应的文件内容。
4. 按需编译
Vite 在接收到浏览器对某个模块的请求时,会实时编译该模块。对于 JavaScript 文件,Vite 使用 esbuild 进行超快速的编译;对于其他文件类型(如 Vue、React 组件),Vite 使用相应的预处理器(如 @vitejs/plugin-vue 或 @vitejs/plugin-react)进行编译。
5. 热模块替换(HMR)
Vite 内置了高效的 HMR 支持,通过 WebSocket 连接浏览器和开发服务器。当源文件发生变化时,Vite 只重新编译变化的模块,并将新的模块推送到浏览器,实现局部更新而不刷新整个页面。
6. Source Maps
在开发模式下,Vite 自动生成 Source Maps,帮助开发者进行调试。这使得浏览器能够映射编译后的代码到源代码,提高调试的效率。
Vite 构建过程(Vite Build)
1. 项目初始化
与开发模式类似,构建过程同样从读取和解析 vite.config.js 配置文件开始,进行初始化配置。
2. 入口解析
Vite 使用 Rollup 作为其底层打包工具。在构建开始时,Vite 会将项目的入口文件传递给 Rollup。Rollup 从入口文件出发,递归解析所有的依赖模块,构建模块依赖图。
3. 插件处理
Vite 和 Rollup 的插件系统在构建过程中起到关键作用。插件可以在不同的构建阶段对代码进行处理,如:
- 代码转换 : 使用 Babel 或 TypeScript 将源代码转换为浏览器兼容的 JavaScript 代码。
- 代码压缩 : 使用 Terser 对 JavaScript 代码进行压缩,减少文件体积。
- CSS 处理 : 使用 PostCSS 对 CSS 进行预处理、合并和压缩。
- 资源处理 : 处理静态资源(图片、字体等),将它们转换为适合生产环境使用的格式。
4. Tree Shaking
Rollup 的 Tree Shaking 功能在构建过程中移除未使用的代码,确保最终的打包产物中只包含实际需要的部分。Tree Shaking 通过静态分析模块的导入和导出,删除那些没有被引用的代码。
5. 代码拆分
为了优化加载性能,Vite 支持代码拆分。Rollup 会根据模块的依赖关系,将代码拆分成多个模块块(chunks)。这些模块块在生产环境中可以按需加载,减少初始加载时间。
6. 生成输出
Rollup 将所有的模块块进行打包,生成最终的输出文件。输出文件会根据配置文件中的 output 选项进行分类,通常包括:
index.html: 入口 HTML 文件。main.js: 主入口 JavaScript 文件。vendor.js: 第三方依赖。common.js: 公共模块。
7. 资源优化
在构建过程中,Vite 对静态资源进行优化处理:
- CSS 文件 : 合并和压缩 CSS 文件,生成最终的 CSS 文件,并为其生成 Source Map。
- 静态资源 : 压缩图片、字体等资源,并为这些资源生成合适的文件名(包括内容哈希),以便于缓存管理。
8. 缓存策略
Vite 会为生成的静态资源文件添加内容哈希,确保浏览器在文件内容发生变化时能够正确更新缓存。这有助于浏览器有效管理缓存,提升页面加载性能。
总结
Vite 本地开发服务
- 项目初始化 :读取并解析
vite.config.js配置文件。 - 启动开发服务器 :基于 express 启动 HTTP 服务器。
- ESM 支持 :利用浏览器的原生 ESM 进行模块加载。
- 按需编译 :实时编译请求的模块。
- 热模块替换(HMR) :通过 WebSocket 实现模块的局部更新。
- Source Maps :自动生成 Source Maps,便于调试。
Vite 构建过程
- 项目初始化 :读取并解析
vite.config.js配置文件。 - 入口解析 :使用 Rollup 构建模块依赖图。
- 插件处理 :通过插件系统进行代码转换、压缩和资源处理。
- Tree Shaking :移除未使用的代码。
- 代码拆分 :将代码拆分成多个模块块。
- 生成输出 :打包生成最终的输出文件。
- 资源优化 :优化 CSS 和静态资源。
- 缓存策略 :为静态资源添加内容哈希,便于缓存管理。
Vite 源码核心实现
我们实现本地开发构建,使用 esbuild 作为 TypeScript 编译器并在服务器上实时编译 TypeScript 文件。
项目结构
项目基础结构
/my-project
|-- src
| |-- index.html
| |-- index.ts
| |-- hello.ts
|-- tsconfig.json
|-- package.json
|-- server.js
Typescript 配置
{
"compilerOptions": {
"target": "ES6",
"module": "ES6",
"outDir": "./dist",
"rootDir": "./src",
"moduleResolution": "node"
},
"include": ["src/**/*"]
}
安装依赖
我们需要安装 express 和 esbuild 来搭建服务器并进行 TypeScript 编译。
npm install express esbuild @types/express --save-dev
编写 server( server.js )
我们将使用 esbuild 的 API 来动态编译 TypeScript。这里的服务器将处理对 .ts 文件的请求,并在浏览器请求时即时编译它们。
server.js :
const express = require("express");
const esbuild = require("esbuild");
const fs = require("fs");
const path = require("path");
const app = express();
const port = 3000;
app.get("/", (req, res) => {
res.sendFile(__dirname + "/src/index.html");
});
app.get("/*.ts", async (req, res) => {
try {
const reqPath = req.path;
const file = fs.readFileSync(
path.join(__dirname, "src", reqPath),
"utf8"
);
const result = await esbuild.transform(file, {
loader: "ts",
format: "esm",
target: "es2017",
});
res.type("js");
res.send(result.code);
} catch (error) {
console.error(error);
res.status(500).send("Server error");
}
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
定义 HTML 文件 ( src/index.html )
修改 HTML 文件,使其直接请求 TypeScript 文件。浏览器将收到经过 esbuild 编译后的 JavaScript 代码。
index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TypeScript Module Example</title>
</head>
<body>
<script type="module" src="/src/index.ts"></script>
</body>
</html>
运行项目
启动服务器,然后在浏览器中访问 http://localhost:3000 来查看结果。
node server.js
或者指定 package.json,通过脚本命令启动服务
{
"scripts": {
"dev": "node server.js"
}
}
其实我们现在离 vite 实现还差一步,就是命令行工具,通过命令行工具,我们才能真正让 流程自动化起来
【 专家级 】面试官:如果让你设计一个打包工具,你怎么设计? |
设计目标
- 快速开发启动 :利用 ES 模块加载,尽量减少服务器启动时间。
- HMR(热模块替换) :支持快速反映文件更改,无需重新加载整个页面。
- 插件化架构 :允许通过插件扩展功能,提高工具的灵活性和可扩展性。
- 生产构建优化 :使用像 Rollup 这样的高级打包工具来进行代码拆分、压缩和优化。
- 编译侧能力 :编译工具的 sourcemap、tree-shaking、chunk 机制
- 运行时优化 :模块缓存、hmr 等
核心架构组件
开发服务器
开发服务器应能处理 HTTP 请求并根据需要提供 ES 模块。使用 Node.js 的 http 模块可以快速启动基本服务器,同时处理文件的即时转译。
插件系统
设计一个灵活的插件系统,使得功能如预处理、HMR、压缩等可以轻易地添加或修改。
插件协议
export interface Plugin<A = any> extends RollupPlugin<A> {
/**
* Enforce plugin invocation tier similar to webpack loaders. Hooks ordering
* is still subject to the `order` property in the hook object.
*
* Plugin invocation order:
* - alias resolution
* - `enforce: 'pre'` plugins
* - vite core plugins
* - normal plugins
* - vite build plugins
* - `enforce: 'post'` plugins
* - vite build post plugins
*/
enforce?: 'pre' | 'post'
/**
* Apply the plugin only for serve or build, or on certain conditions.
*/
apply?:
| 'serve'
| 'build'
| ((this: void, config: UserConfig, env: ConfigEnv) => boolean)
/**
* Modify vite config before it's resolved. The hook can either mutate the
* passed-in config directly, or return a partial config object that will be
* deeply merged into existing config.
*
* Note: User plugins are resolved before running this hook so injecting other
* plugins inside the `config` hook will have no effect.
*/
config?: ObjectHook<
(
this: void,
config: UserConfig,
env: ConfigEnv,
) =>
| Omit<UserConfig, 'plugins'>
| null
| void
| Promise<Omit<UserConfig, 'plugins'> | null | void>
>
/**
* Use this hook to read and store the final resolved vite config.
*/
configResolved?: ObjectHook<
(this: void, config: ResolvedConfig) => void | Promise<void>
>
/**
* Configure the vite server. The hook receives the {@link ViteDevServer}
* instance. This can also be used to store a reference to the server
* for use in other hooks.
*
* The hooks will be called before internal middlewares are applied. A hook
* can return a post hook that will be called after internal middlewares
* are applied. Hook can be async functions and will be called in series.
*/
configureServer?: ObjectHook<ServerHook>
/**
* Configure the preview server. The hook receives the {@link PreviewServer}
* instance. This can also be used to store a reference to the server
* for use in other hooks.
*
* The hooks are called before other middlewares are applied. A hook can
* return a post hook that will be called after other middlewares are
* applied. Hooks can be async functions and will be called in series.
*/
configurePreviewServer?: ObjectHook<PreviewServerHook>
/**
* Transform index.html.
* The hook receives the following arguments:
*
* - html: string
* - ctx?: vite.ServerContext (only present during serve)
* - bundle?: rollup.OutputBundle (only present during build)
*
* It can either return a transformed string, or a list of html tag
* descriptors that will be injected into the `<head>` or `<body>`.
*
* By default the transform is applied **after** vite's internal html
* transform. If you need to apply the transform before vite, use an object:
* `{ order: 'pre', handler: hook }`
*/
transformIndexHtml?: IndexHtmlTransform
/**
* Perform custom handling of HMR updates.
* The handler receives a context containing changed filename, timestamp, a
* list of modules affected by the file change, and the dev server instance.
*
* - The hook can return a filtered list of modules to narrow down the update.
* e.g. for a Vue SFC, we can narrow down the part to update by comparing
* the descriptors.
*
* - The hook can also return an empty array and then perform custom updates
* by sending a custom hmr payload via server.ws.send().
*
* - If the hook doesn't return a value, the hmr update will be performed as
* normal.
*/
handleHotUpdate?: ObjectHook<
(
this: void,
ctx: HmrContext,
) => Array<ModuleNode> | void | Promise<Array<ModuleNode> | void>
>
/**
* extend hooks with ssr flag
*/
resolveId?: ObjectHook<
(
this: PluginContext,
source: string,
importer: string | undefined,
options: {
attributes: Record<string, string>
custom?: CustomPluginOptions
ssr?: boolean
/**
* @internal
*/
scan?: boolean
isEntry: boolean
},
) => Promise<ResolveIdResult> | ResolveIdResult
>
load?: ObjectHook<
(
this: PluginContext,
id: string,
options?: { ssr?: boolean },
) => Promise<LoadResult> | LoadResult
>
transform?: ObjectHook<
(
this: TransformPluginContext,
code: string,
id: string,
options?: { ssr?: boolean },
) => Promise<TransformResult> | TransformResult
>
}
插件基座
class PluginContainer {
private _pluginContextMap = new Map<Plugin, PluginContext>()
private _pluginContextMapSsr = new Map<Plugin, PluginContext>()
private _resolvedRollupOptions?: InputOptions
private _processesing = new Set<Promise<any>>()
private _seenResolves: Record<string, true | undefined> = {}
private _closed = false
// _addedFiles from the `load()` hook gets saved here so it can be reused in the `transform()` hook
private _moduleNodeToLoadAddedImports = new WeakMap<
ModuleNode,
Set<string> | null
>()
getSortedPluginHooks: PluginHookUtils['getSortedPluginHooks']
getSortedPlugins: PluginHookUtils['getSortedPlugins']
watchFiles = new Set<string>()
minimalContext: MinimalPluginContext
/**
* @internal use `createPluginContainer` instead
*/
constructor(
public config: ResolvedConfig,
public moduleGraph?: ModuleGraph,
public watcher?: FSWatcher,
public plugins = config.plugins,
) {
this.minimalContext = {
meta: {
rollupVersion,
watchMode: true,
},
debug: noop,
info: noop,
warn: noop,
// @ts-expect-error noop
error: noop,
}
const utils = createPluginHookUtils(plugins)
this.getSortedPlugins = utils.getSortedPlugins
this.getSortedPluginHooks = utils.getSortedPluginHooks
}
}
插件执行
async transform(
code: string,
id: string,
options?: {
ssr?: boolean
inMap?: SourceDescription['map']
},
): Promise<{ code: string; map: SourceMap | { mappings: '' } | null }> {
const inMap = options?.inMap
const ssr = options?.ssr
const ctx = new TransformPluginContext(
this,
id,
code,
inMap as SourceMap,
!!ssr,
)
ctx._addedImports = this._getAddedImports(id)
for (const plugin of this.getSortedPlugins('transform')) {
if (this._closed && !ssr) throwClosedServerError()
if (!plugin.transform) continue
ctx._updateActiveInfo(plugin, id, code)
const start = debugPluginTransform ? performance.now() : 0
let result: TransformResult | string | undefined
const handler = getHookHandler(plugin.transform)
try {
result = await this.handleHookPromise(
handler.call(ctx as any, code, id, { ssr }),
)
} catch (e) {
ctx.error(e)
}
if (!result) continue
debugPluginTransform?.(
timeFrom(start),
plugin.name,
prettifyUrl(id, this.config.root),
)
if (isObject(result)) {
if (result.code !== undefined) {
code = result.code
if (result.map) {
if (debugSourcemapCombine) {
// @ts-expect-error inject plugin name for debug purpose
result.map.name = plugin.name
}
ctx.sourcemapChain.push(result.map)
}
}
ctx._updateModuleInfo(id, result)
} else {
code = result
}
}
return {
code,
map: ctx._getCombinedSourcemap(),
}
}
构建系统
在生产环境中,使用像 esbuild 或 rollup 来进行高效的资源优化和打包。
export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
pre: Plugin[]
post: Plugin[]
}> {
const options = config.build
const { commonjsOptions } = options
const usePluginCommonjs =
!Array.isArray(commonjsOptions?.include) ||
commonjsOptions?.include.length !== 0
const rollupOptionsPlugins = options.rollupOptions.plugins
return {
pre: [
completeSystemWrapPlugin(),
...(usePluginCommonjs ? [commonjsPlugin(options.commonjsOptions)] : []),
dataURIPlugin(),
...((await asyncFlatten(arraify(rollupOptionsPlugins))).filter(
Boolean,
) as Plugin[]),
...(config.isWorker ? [webWorkerPostPlugin()] : []),
],
post: [
buildImportAnalysisPlugin(config),
...(config.esbuild !== false ? [buildEsbuildPlugin(config)] : []),
...(options.minify ? [terserPlugin(config)] : []),
...(!config.isWorker
? [
...(options.manifest ? [manifestPlugin(config)] : []),
...(options.ssrManifest ? [ssrManifestPlugin(config)] : []),
buildReporterPlugin(config),
]
: []),
loadFallbackPlugin(),
],
}
}
核心代码设计
下面是基于 Node.js 的简化打包工具的伪代码实现,涵盖了开发服务器、插件系统和基本构建过程。
开发服务器 ( devServer.js )
const http = require('http');
const fs = require('fs');
const path = require('path');
const esbuild = require('esbuild');
// 插件管理器
const plugins = [];
function registerPlugin(plugin) {
plugins.push(plugin);
}
// 服务器逻辑
const server = http.createServer(async (req, res) => {
const filePath = path.join(__dirname, 'src', new URL(req.url, 'http://localhost:3000').pathname);
// 插件处理请求
for (const plugin of plugins) {
if (plugin.handleRequest(req, res)) return;
}
// 默认为 JS 文件使用 esbuild 转换
if (filePath.endsWith('.ts')) {
const transformed = await esbuild.transform(fs.readFileSync(filePath, 'utf8'), {
loader: 'ts',
format: 'esm',
});
res.writeHead(200, { 'Content-Type': 'application/javascript' });
res.end(transformed.code);
} else {
// 静态文件处理
res.writeHead(200);
res.end(fs.readFileSync(filePath, 'utf8'));
}
});
server.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
插件示例 ( plugins/hmrPlugin.js )
function hmrPlugin() {
return {
name: 'hmr',
handleRequest(req, res) {
if (req.url === '/__hmr') {
// 处理 HMR 逻辑
res.writeHead(200, { 'Content-Type': 'application/javascript' });
res.end('console.log("HMR Enabled")');
return true;
}
return false;
}
};
}
配置和启动 ( index.js )
const { registerPlugin } = require('./devServer');
const hmrPlugin = require('./plugins/hmrPlugin');
registerPlugin(hmrPlugin());
require('./devServer');
构建系统 ( build.js )
const esbuild = require('esbuild');
esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
minify: true,
sourcemap: true,
outfile: 'dist/bundle.js',
}).catch(() => process.exit(1));
更多特性
- 插件系统扩展 :根据需要开发更多功能丰富的插件。
- 优化开发服务器 :实现更高效的文件服务逻辑,例如通过缓存来提升响应速度。
- 细化构建策略 :添加代码拆分、环境变量替换、更复杂的资源管理等特性。
妙码学院全网独家项目实战矩阵
所有项目实战,均完全 从零到一手写 , 纯原创 ,项目架构与编码规范真一线大厂级。
微前端在分拆原子应用场景下的落地与实践
协同编辑器从零到一架构实现
推动团队基建落地
- React UI 库
- Vue Composition API 库
- 企业级脚手架
数字孪生平台整体架构设计
企业级无代码可视化平台实践(Vue3)
低代码平台设计与实现
- 编排引擎
- 流程引擎
- 编辑器
- 代码执行器与 JavaScript 沙箱
用户行为分析 SDK 及监控可视化整体实现
可视化渲染引擎设计与实现
基于 RAG / Agent 前端 AI 应用流程编排平台
简历优化(30K+ 简历样板)
技能描述
熟练掌握 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+ 薪资长线规划
核心要素
全面的技术储备
- Vue 经验、React 经验,Vue3 + Typescript,React18(Hooks、Concurrent)【框架基础】
- 框架原理,React 生态库原理(React-Router、Redux)、Vue 生态库原理
- 工程化(构建工具:Webpack、Vite、Rspack、ESBuild、swc)
- CI/CD 自动化,自动化构建、自动化部署
- 基建能力(Node、命令行工具开发 Cli),UI 库、图表库、工具库
- 业务方面(管理系统、图表类),衍生 -> 可视化、编辑器、云表格、低代码、SaaS 产品、数字孪生、三维可视化
至少参加过两个以上大型项目,并主导过一个复杂项目
- 管理系统,(项目搭建、方案、技术栈、CI/CD 等等)
- 可视化、编辑器、云表格、低代码、SaaS 产品、数字孪生、三维可视化
面试表现好
个人介绍【 打个草稿 】,基本信息、技术栈、项目重难点
STAR:
- 遇到了什么问题 question,需求
- 怎么评估解决方案,方案对比,方案落地 react 状态管理(redux、mobx、jotai、recoil)Vue3 -> Pinia
- 方案落地
- 反思,优化
- 面试过程中,重点去复习只是重难点(v8 内存管理、Promise A+ 规范、事件循环、this、面向对象编程原型)
- 技术储备,由你的项目经验体验,技术怎样在你的项目中落地的
学历
- 大专,尽快考一个本科证(年限去掉)
- 民办
- 内推,学历问题、工作经历的问题
补足短板
项目简单,管理后台一做就是大半年,天天 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 可视化开发实践
不同阶段对前端人的硬性要求
以下是对您提供的内容进行权威和专业化改写的建议:
1~3年
在此阶段,重点在于评估个人的基础知识和热情。对前端基础、计算机原理、网络通信和算法等领域的要求较高。由于在此阶段难以评估业务深度,因此更多关注基础知识的掌握程度。
- 关键在于通过学术教育或网络资源加强基础知识;
- 在简历中以多种方式展示对前端的热情,展现个人潜力;
- 积极探索前沿技术,关注国内外技术动态;
- 尝试开发小型项目或参与社区开源项目;
- 建立技术博客,以输出促进知识吸收。
3~5年
此阶段通常是向成为独立工程师发展的关键时期,避免重复使用有限的经验。
关注社区中关于进阶的资料和路线,强化基础知识;
深入掌握常用框架的高级用法,探索其原理;
在业务开发中不仅完成功能,还需考虑项目结构设计、封装基础工具、设计和开发基础组件;
思考提高团队效率的方法,例如:
- 集成代码检验和风格统一插件(如 eslint、stylelint、prettier、spellcheck);
- 从工程化角度提高本地开发效率,优化webpack构建,探索esbuild、vite等工具;
- 对于多项目开发,整理差异和统一部分,建立内部脚手架以减少重复工作;
- 尝试搭建CI/CD平台,维护公司内部的通用npm包;
- 培养软技能,如沟通协作,协调各角色共同推进目标。
5年以上
进入此阶段,可能朝技术专家或管理方向发展。期望您能够独立负责高复杂度项目,突破关键技术难题。
- 负责技术调研,关注行业趋势,选择最优技术方案,具备决策能力;
- 拥有丰富的技术经验和技术储备,能够解决遇到的困难,并有自己的方法论;
- 协助或主导业务目标制定,合理推动项目达成预期效果;
- 是否具有团队领导经验,能够协调跨团队项目,处理团队成员情绪问题,解决技能分布不平衡等问题;
- 打造技术氛围,促进团队共同成长。
职业规划指导
评论区选取三位同学互动,其他同学也可以联系咨询老师,文字方式提供辅导解答。
【未知组件reminder】
