⚠️温馨提示: 文档中包含【1个】暂不支持的区域,请通过搜索关键字【暂不支持的文档区域】进行后续处理
很多同学可能第一次来,我分享了很多干货公开课,希望对你的技术成长有帮助!免费分享都在这里,需要 文档和配套视频找咨询老师 领取~
【飞书文档】备战金九银十,进阶大前端,涨薪全突破! 跳槽涨薪需求同学必看
【飞书文档】面试被算法干吐了?字节大佬带你突破极限,冲击 30K+ 必掌握算法与 WebAssembly 技术 冲刺年包 50W+ 同学必看
【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节【超详细内培版】
【飞书文档】高级前端专家如何做项目架构与工程化设计? 特邀字节大佬细数字节开源项目架构细节【超详细内培版】
【飞书文档】小小微前端,轻松拿捏,特邀字节大佬开讲微前端架构与源码剖析【内部培训版】 35K+ 同学必看
【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节(二)【内部培训版】
【飞书文档】前端破局 AI 应用开发,特邀字节大佬分享字节系 AI 场景落地应用与 AI 引擎编排流程 探索前端新方向同学福音
【飞书文档】React18 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题
【飞书文档】Vue3 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题
【飞书文档】Vite 构建过程与源码深度剖析,你怎么也想不到一线大厂工程化构建面试会问这么深!
- 【 初中级 】面试官:了解过脚手架/命令行工具开发吗,简要说明开发要点
- 【 中高级 】面试官:说说你们团队的 团队基建 ,开发脚手架的目的与方案
- 【 专家级 】面试官:作为 Leader,详述脚手架开发方案、技术细节与命令设计
【 初中级 】面试官:了解过脚手架/命令行工具开发吗,简要说明开发要点 |
Node 应用开发步骤详解
开发 Node 应用与 React、Vue 略有区别,React、Vue 应用开发我们更关注 UI 表现,而 Node 应用开发我们更关注的是整体业务流程,比如我们的目的是通过命令行工具简化开发,那么命令行工具的设计思路便是来源于日常开发工作,命令行工具开发的目的便是解决实际开发过程中的问题的。
创建项目
首先,使用 npm 初始化一个新的 Node.js 项目:
mkdir miaoma-cli
cd miaoma-cli
npm init -y
这将创建一个基本的 package.json 文件。
指定依赖
接下来,我们需要安装一些依赖。通常,开发脚手架工具需要一些实用的 npm 包:
"devDependencies": {
"commander": "12.1.0",
"picocolors": "1.0.1",
"prompts": "2.4.2",
"table": "6.8.2",
"handlebars": "4.7.8"
}
定义 scripts
在 package.json 中,我们可以定义一些脚本来简化常用的命令。例如:
{
"name": "@miaoma/cli",
"version": "1.0.0",
"description": "A simple CLI tool",
"main": "index.js",
"bin": {
"miao": "./index.js"
},
"scripts": {
"start": "node index.js"
},
"devDependencies": {
"commander": "12.1.0",
"picocolors": "1.0.1",
"prompts": "2.4.2",
"table": "6.8.2",
"handlebars": "4.7.8"
}
}
在这里, bin 字段定义了全局命令 miao ,它将执行 index.js 文件。
- main
- module
- types
- bin
- files
执行脚本
创建一个简单的 index.js 文件来演示脚手架的基本功能:
#!/usr/bin/env node
const { program } = require('commander');
const pc = require('picocolors');
const prompts = require('prompts');
const { table } = require('table');
const Handlebars = require('handlebars');
// Commander program setup
program
.version('1.0.0')
.description('A simple CLI tool');
// Greet command using prompts
program
.command('greet')
.description('Greet the user')
.action(async () => {
const response = await prompts({
type: 'text',
name: 'name',
message: 'What is your name?',
});
console.log(pc.green(`Hello, ${response.name}!`));
});
// Table command using console-table-printer
program
.command('table')
.description('Print a table')
.action(() => {
const data = [['0A', '0B', '0C'],['1A', '1B', '1C'],['2A', '2B', '2C']];
console.log(table(data));
});
// Template command using Handlebars
program
.command('template')
.description('Render a template')
.action(() => {
const template = Handlebars.compile('Hello, {{name}}!');
const result = template({ name: 'World' });
console.log(result);
});
program.parse(process.argv);
确保文件具有可执行权限:
chmod +x index.js
开发脚手架的核心依赖说明
commander
用于命令行参数解析的 commander 是一个功能强大的库,支持命令和选项的定义。
const { program } = require('commander');
// 设置版本和描述
program
.version('1.0.0')
.description('A simple CLI tool');
// 定义一个选项
program
.option('-n, --name <type>', 'specify name');
// 处理命令行输入
program.parse(process.argv);
if (program.name) {
console.log(`Hello, ${program.name}`);
}
commander API 使用与原理
program.version(version, [flags], [description]): 设置CLI的版本信息。program.description(description): 设置CLI的描述信息。program.option(flags, description, [defaultValue]): 定义选项,flags包含短选项和长选项。program.command(name, [description]): 定义子命令。program.parse(argv): 解析命令行参数,通常是process.argv。
picocolors
用于处理命令行颜色高亮的 picocolors 是一个轻量级的库。
const pc = require('picocolors');
console.log(pc.green('Success!'));
console.log(pc.red('Error!'));
console.log(pc.blue('Information!'));
prompts
用于交互式提问的 prompts ,可以根据用户输入动态生成问题。
const prompts = require('prompts');
(async () => {
const response = await prompts({
type: 'text',
name: 'username',
message: 'What is your name?'
});
console.log(`Hello, ${response.username}`);
})();
复杂场景的使用
const prompts = require('prompts');
prompts.override(require('yargs').argv);
(async () => {
const response = await prompts([
{
type: 'text',
name: 'twitter',
message: `What's your twitter handle?`
},
{
type: 'multiselect',
name: 'color',
message: 'Pick colors',
choices: [
{ title: 'Red', value: '#ff0000' },
{ title: 'Green', value: '#00ff00' },
{ title: 'Blue', value: '#0000ff' }
],
}
]);
console.log(response);
})();
常用 API
type: 问题类型,如text、select、multiselect等。name: 用于存储答案的字段名。message: 提示消息。choices: 多选题目时的选项数组。
table
用于展示表格内容的 table 可以帮助我们在命令行中美观地打印表格。
const { table } = require('table');
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
console.log(table(data));
常用 API
table
返回表格格式的字符串。
参数:
- data : 要显示的数据 (类型:
any[][], 必填) - config : 表格配置 (类型:
object, 可选)
示例:
const data = [
['0A', '0B', '0C'],
['1A', '1B', '1C'],
['2A', '2B', '2C']
];
const config = {
border: {
topBody: `─`,
topJoin: `┬`,
topLeft: `┌`,
topRight: `┐`,
bottomBody: `─`,
bottomJoin: `┴`,
bottomLeft: `└`,
bottomRight: `┘`,
bodyLeft: `│`,
bodyRight: `│`,
bodyJoin: `│`,
joinBody: `─`,
joinLeft: `├`,
joinRight: `┤`,
joinJoin: `┼`
}
};
console.log(table(data, config));
输出:
┌────┬────┬────┐
│ 0A │ 0B │ 0C │
├────┼────┼────┤
│ 1A │ 1B │ 1C │
├────┼────┼────┤
│ 2A │ 2B │ 2C │
└────┴────┴────┘
config.drawVerticalLine
决定是否绘制垂直线。
类型: (lineIndex: number, columnCount: number) => boolean \
默认: () => true
const config = {
drawVerticalLine: (lineIndex, columnCount) => {
return lineIndex === 0 || lineIndex === columnCount;
}
};
console.log(table(data, config));
输出:
╔════════════╗
║ 0A 0B 0C ║
╟────────────╢
║ 1A 1B 1C ║
╟────────────╢
║ 2A 2B 2C ║
╟────────────╢
║ 3A 3B 3C ║
╟────────────╢
║ 4A 4B 4C ║
╚════════════╝
config.drawHorizontalLine
决定是否绘制水平线。
类型: (lineIndex: number, rowCount: number) => boolean \
默认: () => true
const config = {
drawHorizontalLine: (lineIndex, rowCount) => {
return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount - 1 || lineIndex === rowCount;
}
};
console.log(table(data, config));
输出:
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
║ 2A │ 2B │ 2C ║
║ 3A │ 3B │ 3C ║
╟────┼────┼────╢
║ 4A │ 4B │ 4C ║
╚════╧════╧════╝
config.singleLine
设置为 true 时,不绘制表格内的水平线。
类型: boolean \
默认: false
const config = {
singleLine: true
};
console.log(table(data, config));
输出:
╔═════════════╤═════╤══════════╤═══════╤════════╤══════════════╤═══════════════════╗
║ -rw-r--r-- │ 1 │ pandorym │ staff │ 1529 │ May 23 11:25 │ LICENSE ║
║ -rw-r--r-- │ 1 │ pandorym │ staff │ 16327 │ May 23 11:58 │ README.md ║
║ drwxr-xr-x │ 76 │ pandorym │ staff │ 2432 │ May 23 12:02 │ dist ║
║ drwxr-xr-x │ 634 │ pandorym │ staff │ 20288 │ May 23 11:54 │ node_modules ║
║ -rw-r--r-- │ 1, │ pandorym │ staff │ 525688 │ May 23 11:52 │ package-lock.json ║
║ -rw-r--r--@ │ 1 │ pandorym │ staff │ 2440 │ May 23 11:25 │ package.json ║
║ drwxr-xr-x │ 27 │ pandorym │ staff │ 864 │ May 23 11:25 │ src ║
║ drwxr-xr-x │ 20 │ pandorym │ staff │ 640 │ May 23 11:25 │ test ║
╚═════════════╧═════╧══════════╧═══════╧════════╧══════════════╧═══════════════════╝
config.columns
列特定配置。
示例: 设置列宽度
const config = {
columns: {
1: { width: 10 }
}
};
console.log(table(data, config));
输出:
╔════╤════════════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────────────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────────────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════════════╧════╝
示例: 设置列对齐方式
const config = {
columnDefault: {
width: 10,
},
columns: [
{ alignment: 'left' },
{ alignment: 'center' },
{ alignment: 'right' },
{ alignment: 'justify' }
],
};
console.log(table(data, config));
输出:
╔════════════╤════════════╤════════════╤════════════╗
║ 0A │ 0B │ 0C │ 0D 0E 0F ║
╟────────────┼────────────┼────────────┼────────────╢
║ 1A │ 1B │ 1C │ 1D 1E 1F ║
╟────────────┼────────────┼────────────┼────────────╢
║ 2A │ 2B │ 2C │ 2D 2E 2F ║
╚════════════╧════════════╧════════════╧════════════╝
示例: 设置列内容截断
const config = {
columns: [
{
width: 20,
truncate: 100
}
]
};
console.log(table(data, config));
输出:
╔══════════════════════╗
║ Lorem ipsum dolor si ║
║ t amet, consectetur ║
║ adipiscing elit. Pha ║
║ sellus pulvinar nibh ║
║ sed mauris convall… ║
╚══════════════════════╝
createStream
使用 createStream 函数创建并追加行的表格。
参数:
- config: 与
table相同,但必须提供config.columnDefault.width和config.columnCount。
示例:
import { createStream } from 'table';
const config = {
columnDefault: {
width: 50
},
columnCount: 1
};
const stream = createStream(config);
setInterval(() => {
stream.write([new Date()]);
}, 500);
getBorderCharacters
加载预定义的边框模板。
参数:
-
template (类型: 'honeywell' | 'norc' | 'ramac' | 'void' , 必填)
示例:
import { table, getBorderCharacters } from 'table';
const config = {
border: getBorderCharacters(`honeywell`)
};
console.log(table(data, config));
输出:
╔════╤════╤════╗
║ 0A │ 0B │ 0C ║
╟────┼────┼────╢
║ 1A │ 1B │ 1C ║
╟────┼────┼────╢
║ 2A │ 2B │ 2C ║
╚════╧════╧════╝
handlebars
用于模板处理的 handlebars 可以生成动态内容。
const Handlebars = require('handlebars');
const template = Handlebars.compile('Hello, {{name}}!');
const result = template({ name: 'World' });
console.log(result);
常用 API
compile(template): 编译模板字符串。- 编译后的模板函数可以接受一个对象作为参数,并返回生成的字符串。
通过这些步骤,我们可以构建一个功能丰富的命令行工具,并利用上述库实现参数解析、颜色高亮、交互提问、表格展示和模板处理等功能。
【 中高级 】面试官:说说你们团队的团队基建,开发脚手架的目的与方案 |
好的,以下是一个更详实的回答,包括技术点和项目模板的定义与使用:
团队基建的定义
团队基建(Team Infrastructure)是指团队在软件开发过程中所依赖的一系列工具、系统和流程。这些基建能够提高开发效率、确保代码质量并促进团队协作。
团队基建的目的
- 提高开发效率 :通过自动化工具和脚手架,减少重复性劳动,使开发人员能够更专注于业务逻辑和功能实现。
- 确保代码质量 :通过代码规范检查、自动化测试等手段,确保代码的一致性和可靠性。
- 促进团队协作 :提供统一的开发环境和工具,确保团队成员在相同的基础上工作,减少环境差异带来的问题。
- 简化维护和升级 :通过标准化的工具和流程,使得代码库的维护和升级变得更加容易。
开发脚手架的目的
- 快速搭建项目结构 :提供标准化的项目结构和配置,减少初始设置的时间。
- 统一开发规范 :通过预配置的代码规范检查工具(如 ESLint、Prettier 等),确保团队成员遵循相同的编码标准。
- 集成常用功能 :预先集成常用的功能模块(如用户认证、日志记录等),使得开发人员可以快速上手,减少重复造轮子的时间。
- 自动化流程 :集成 CI/CD 管道、自动化测试、代码部署等流程,确保代码在每次提交后都能自动进行测试和部署。
开发脚手架的方案
需求分析
- 确定需求 :与团队成员沟通,确定开发过程中常见的需求和痛点。
- 功能列表 :列出脚手架需要实现的功能,如项目初始化、代码规范检查、自动化测试等。
技术选型
- 工具选择 :选择适合的工具和技术栈,如 Yeoman、Plop 等脚手架生成工具。
- 框架和库 :选择合适的前后端框架和库,如 React、Vue、Express 等。
脚手架实现
项目模板 :创建标准化的项目模板,包括文件结构、配置文件等。
项目模板可以包括以下内容:
- 基本文件结构 :如 src、test、config 等目录。
- 配置文件 :如 package.json、webpack.config.js 等。
- 示例代码 :如示例组件、服务、路由等。
脚本编写 :编写脚本实现项目初始化、依赖安装、代码生成等功能。
- 使用
commander(版本 12.1.0)作为命令行接口框架。 - 使用
picocolors(版本 1.0.1)处理命令行输出的颜色。 - 使用
prompts(版本 2.4.2)进行交互式命令行提示。 - 使用
table(版本 6.8.2)格式化输出表格数据。 - 使用
handlebars(版本 4.7.8)进行模板渲染。
- 使用
测试和验证
- 功能测试 :对脚手架的各项功能进行测试,确保其正确性和稳定性。
- 用户反馈 :邀请团队成员使用脚手架,收集反馈意见进行改进。
文档和培训
- 使用文档 :编写详细的使用文档,指导团队成员如何使用脚手架。
- 培训和支持 :为团队成员提供培训和技术支持,确保他们能够熟练使用脚手架。
命令设计
我们的脚手架工具设计了多个命令,类似于 vue-create,以便用户灵活使用:
- 项目初始化
miao create <project-name> [options]
- 示例:
miao create my-project --template react
该命令用于创建新项目,可以选择模板(如 React、Vue、Express 等)。
添加模块
miao add <module-name>
- 示例:
miao add auth
该命令用于向现有项目中添加常用模块,如用户认证、日志记录等。
生成代码
miao generate <type> <name>
- 示例:
miao generate component Header
该命令用于生成不同类型的代码文件,如组件、服务、路由等。
启动开发服务器
miao serve
- 示例:
miao serve --port 3000
该命令用于启动本地开发服务器,支持自定义端口配置。
运行测试
miao test
- 示例:
miao test --watch
该命令用于运行项目的自动化测试,支持监视模式。
构建项目
miao build
- 示例:
miao build --mode production
该命令用于构建项目,支持不同环境的配置,如生产环境和开发环境。
部署项目
miao deploy
- 示例:
miao deploy --target staging
- 该命令用于将项目部署到指定环境,如测试环境、生产环境等。
这些命令通过 commander 实现,并且结合 prompts 进行交互式提示,帮助用户快速配置项目。输出信息使用 picocolors 增加可读性,表格数据通过 table 格式化展示,模板渲染由 handlebars 完成。
示例回答
“我们团队的团队基建主要包括代码规范检查、自动化测试和持续集成。开发脚手架的主要目的是提高开发效率和代码质量。用到了 commander 作为命令行接口框架,picocolors 处理命令行输出的颜色,prompts 进行交互式命令行提示,table 格式化输出表格数据,以及 handlebars 进行模板渲染。
我们定义了标准化项目模板,包括基本文件结构、配置文件和示例代码,并编写了脚本实现项目初始化、依赖安装和代码生成功能。
通过使用这个脚手架,我们显著减少了项目初始化的时间,统一了代码规范,并且保证了每次代码提交后的质量和稳定性。团队成员可以通过 miao create 命令快速生成标准化的项目结构,并选择所需的模板和配置。通过 miao add auth ,可以轻松添加用户认证模块,而无需重复编写代码。 miao generate component Header 则可以快速生成符合团队规范的组件代码。
我们还编写了详细的使用文档,并进行了团队培训,确保每个成员都能熟练使用这个工具。
【 专家级 】面试官:作为 Leader,详述脚手架开发方案、技术细节与命令设计 |
脚手架开发方案
需求分析 :
- 首先需要支持前端不同模板(如 react-ts、vue-ts 等)
- 提供本地和远程模板拉取的功能
技术选型 :
- 选择合适的编程语言和工具库(如Node.js的Commander、Prompts、Picocolors、Handlebars等)
- 选择模板引擎(如Handlebars)用于生成代码模板
项目结构设计 :
- 使用monorepo架构,并使用 pnpm workspace 进行管理
技术细节
项目初始化 :
- 创建一个pnpm项目,安装必要的依赖:
mkdir miaoma-cli cd miaoma-cli pnpm init目录结构 :
- 示例项目结构:
miaoma-cli/ ├── packages/ │ ├── cli/ │ │ ├── bin/ │ │ │ └── miao.js │ │ ├── src/ │ │ │ ├── commands/ │ │ │ │ └── init.js │ │ │ ├── utils/ │ │ │ │ └── templateUtils.js │ │ │ └── index.js │ │ ├── package.json │ ├── templates/ │ │ ├── react-ts/ │ │ │ └── template-files │ │ ├── vue-ts/ │ │ │ └── template-files ├── package.json └── pnpm-workspace.yamlpnpm workspace 配置 (pnpm-workspace.yaml):
packages:
- 'packages/*'
- 依赖安装
"devDependencies": {
"commander": "12.1.0",
"picocolors": "1.0.1",
"prompts": "2.4.2",
"table": "6.8.2",
"handlebars": "4.7.8"
}
- CLI 入口文件 (packages/cli/bin/miao.js):
#!/usr/bin/env node
import { program } from 'commander';
import { initCommand } from '../src/commands/init.js';
program
.version('1.0.0')
.command('init <project-name>')
.description('initialize a new project')
.action(initCommand);
program.parse(process.argv);
- 初始化命令实现 (packages/cli/src/commands/init.js):
import fs from 'fs-extra';
import path from 'path';
import { promisify } from 'util';
import prompts from 'prompts';
import picocolors from 'picocolors';
import { cloneRepo, copyTemplateFiles } from '../utils/templateUtils.js';
const access = promisify(fs.access);
export async function initCommand(projectName) {
const response = await prompts([
{
type: 'select',
name: 'projectType',
message: 'Select project type:',
choices: [
{ title: 'React-TS', value: 'react-ts' },
{ title: 'Vue-TS', value: 'vue-ts' }
]
},
{
type: 'select',
name: 'templateSource',
message: 'Select template source:',
choices: [
{ title: 'Local', value: 'local' },
{ title: 'Remote', value: 'remote' }
]
},
{
type: prev => prev === 'remote' ? 'text' : null,
name: 'repoUrl',
message: 'Enter the git repository URL:'
}
]);
const projectPath = path.join(process.cwd(), projectName);
try {
await access(projectPath);
console.error(picocolors.red(`Project directory ${projectName} already exists.`));
process.exit(1);
} catch (err) {
fs.mkdirSync(projectPath);
}
if (response.templateSource === 'local') {
const templatePath = path.join(__dirname, `../../../templates/${response.projectType}`);
copyTemplateFiles(templatePath, projectPath);
} else {
const repoUrl = response.repoUrl;
await cloneRepo(repoUrl, projectPath);
}
console.log(picocolors.green(`Project ${projectName} initialized successfully!`));
}
- 模板工具函数 (packages/cli/src/utils/templateUtils.js):
import fs from 'fs-extra';
import path from 'path';
import handlebars from 'handlebars';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
export function copyTemplateFiles(templatePath, targetPath) {
fs.copySync(templatePath, targetPath, {
filter: (src, dest) => {
if (fs.lstatSync(src).isFile() && src.endsWith('.hbs')) {
const content = fs.readFileSync(src, 'utf-8');
const result = handlebars.compile(content)({});
fs.writeFileSync(dest.replace('.hbs', ''), result);
return false;
}
return true;
}
});
}
export async function cloneRepo(repoUrl, targetPath) {
await execAsync(`git clone ${repoUrl} ${targetPath}`);
}
命令设计
命令格式 :
miao init <project-name>:初始化一个新项目。- 示例:
miao init my-project
- 示例:
根据需求,可以设计更多命令,比如
add命令添加新的模块、generate命令生成特定组件等。
选项与参数 :
-v, --version:查看脚手架版本。-h, --help:查看帮助信息。- 其他自定义选项可以根据需要添加。
插件体系设计
修改项目结构,以支持插件化体系脚手架实现
将插件系统独立为子包,可以更好地进行管理和维护。下面是根据你的要求,将插件系统独立为子包的实现方案。
项目结构:
miaoma-cli/
├── packages/
│ ├── cli/
│ │ ├── bin/
│ │ │ └── miao.js
│ │ ├── src/
│ │ │ ├── commands/
│ │ │ │ └── init.js
│ │ │ ├── utils/
│ │ │ │ └── templateUtils.js
│ │ │ └── index.js
│ │ ├── package.json
│ ├── plugins/
│ │ ├── src/
│ │ │ ├── index.js
│ │ │ ├── pluginA.js
│ │ │ └── pluginB.js
│ │ ├── package.json
│ ├── templates/
│ │ ├── react-ts/
│ │ │ └── template-files
│ │ ├── vue-ts/
│ │ │ └── template-files
├── package.json
└── pnpm-workspace.yaml
- 插件系统主文件 (packages/plugins/src/index.js):
import fs from 'fs-extra';
import path from 'path';
const plugins = {};
export function registerPlugin(pluginName, plugin) {
plugins[pluginName] = plugin;
}
export function loadPlugins() {
const pluginsDir = path.join(__dirname);
fs.readdirSync(pluginsDir).forEach(file => {
if (file !== 'index.js') {
const plugin = require(path.join(pluginsDir, file));
if (plugin && plugin.name && plugin.apply) {
registerPlugin(plugin.name, plugin.apply);
}
}
});
}
export function applyPlugins(hook, ...args) {
Object.values(plugins).forEach(plugin => {
if (typeof plugin[hook] === 'function') {
plugin[hook](...args);
}
});
}
- 插件示例 (packages/plugins/src/pluginA.js):
export const name = 'pluginA';
export function apply(hook, ...args) {
if (hook === 'beforeInit') {
console.log('pluginA: beforeInit hook called');
} else if (hook === 'afterInit') {
console.log('pluginA: afterInit hook called');
}
}
- CLI 中使用插件系统 (packages/cli/src/commands/init.js):
import fs from 'fs-extra';
import path from 'path';
import { promisify } from 'util';
import prompts from 'prompts';
import picocolors from 'picocolors';
import { cloneRepo, copyTemplateFiles } from '../utils/templateUtils.js';
import { loadPlugins, applyPlugins } from '@miaoma/plugins';
const access = promisify(fs.access);
loadPlugins();
export async function initCommand(projectName) {
applyPlugins('beforeInit', projectName);
const response = await prompts([
{
type: 'select',
name: 'projectType',
message: 'Select project type:',
choices: [
{ title: 'React-TS', value: 'react-ts' },
{ title: 'Vue-TS', value: 'vue-ts' }
]
},
{
type: 'select',
name: 'templateSource',
message: 'Select template source:',
choices: [
{ title: 'Local', value: 'local' },
{ title: 'Remote', value: 'remote' }
]
},
{
type: prev => prev === 'remote' ? 'text' : null,
name: 'repoUrl',
message: 'Enter the git repository URL:'
}
]);
const projectPath = path.join(process.cwd(), projectName);
try {
await access(projectPath);
console.error(picocolors.red(`Project directory ${projectName} already exists.`));
process.exit(1);
} catch (err) {
fs.mkdirSync(projectPath);
}
if (response.templateSource === 'local') {
const templatePath = path.join(__dirname, `../../../templates/${response.projectType}`);
copyTemplateFiles(templatePath, projectPath);
} else {
const repoUrl = response.repoUrl;
await cloneRepo(repoUrl, projectPath);
}
console.log(picocolors.green(`Project ${projectName} initialized successfully!`));
applyPlugins('afterInit', projectName);
}
- CLI 入口文件 (packages/cli/bin/miao.js):
#!/usr/bin/env node
import { program } from 'commander';
import { initCommand } from '../src/commands/init.js';
program
.version('1.0.0')
.command('init <project-name>')
.description('initialize a new project')
.action(initCommand);
program.parse(process.argv);
- 模板工具函数 (packages/cli/src/utils/templateUtils.js):
import fs from 'fs-extra';
import path from 'path';
import handlebars from 'handlebars';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
export function copyTemplateFiles(templatePath, targetPath) {
fs.copySync(templatePath, targetPath, {
filter: (src, dest) => {
if (fs.lstatSync(src).isFile() && src.endsWith('.hbs')) {
const content = fs.readFileSync(src, 'utf-8');
const result = handlebars.compile(content)({});
fs.writeFileSync(dest.replace('.hbs', ''), result);
return false;
}
return true;
}
});
}
export async function cloneRepo(repoUrl, targetPath) {
await execAsync(`git clone ${repoUrl} ${targetPath}`);
}
扩展与优化
模板管理 :
- 支持用户自定义模板,提供下载和更新模板的功能。
- 使用Git管理模板仓库,用户可以通过命令从远程仓库更新模板。
错误处理 :
- 增加详细的错误处理和提示信息,提升用户体验。
测试与文档 :
- 编写单元测试和集成测试,确保脚手架功能的稳定性。
- 提供详细的使用文档和示例,帮助用户快速上手。
妙码学院全网独家项目实战矩阵
所有项目实战,均完全 从零到一手写 , 纯原创 ,项目架构与编码规范真一线大厂级。
微前端在分拆原子应用场景下的落地与实践
协同编辑器从零到一架构实现
推动团队基建落地
- 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.js、命令行工具开发(Cli)
- UI 库、图表库、工具库开发
业务领域经验
- 管理系统和图表类应用
- 可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
项目经验
- 参与过至少两个大型项目,并主导过一个复杂项目
- 管理系统:包括项目搭建、技术方案选择、技术栈构建、CI/CD 流程
- 其他领域项目:如可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
面试表现
个人介绍
- 准备个人介绍草稿,涵盖基本信息、技术栈和项目重难点
STAR 法则
- 问题描述:阐述遇到的问题或需求
- 解决方案评估:方案对比与选择(如 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】
