如何搭建一个前端脚手架

为什么我们需要脚手架?

  • 对于前端来说,从零开始建立一个项目是复杂的
  • 完成新项目的启动和搭建,能够帮助开发者提升效率和开发体验

前置准备

  • inquirer、enquirer、prompts:可以处理复杂的用户输入,完成命令行输入交互。
  • chalk:使终端可以输出彩色信息文案。
  • arg:可以进行基础的命令行参数解析。
  • commander、yargs:可以进行更加复杂的命令行参数解析。

项目创建过程

创建初始化项目
mkdir cli && cd cli
npm init --yes
创建cli函数

创建src目录及src/cli.js文件,cli.js文件内容如下

export function cli(args) {
 console.log(args);
}
创建入口文件

创建src/bin/index.js,为了能够正常使用esm 模块,我们需要先安装,执行npm install esm

#!/usr/bin/env node

require = require('esm')(module /*, options*/);

require('../src/cli').cli(process.argv);
此时使用npm link就能在终端使用xbc执行脚本啦
{
 "name": "xbc-cli",
 "version": "1.0.0",
 "main": "src/index.js",
 "bin": {
   "xbc": "bin/index.js"
 },
 "dependencies": {
   "esm": "^3.2.18"
 }
}
解析处理命令行输入

在解析处理命令行输入之前,我们需要设计命令行支持的几个选项,如下。

  • [template]:支持默认的几种模板类型,用户可以通过 select 进行选择。
  • --git:等同于git init去创建一个新的 Git 项目。
  • --install:支持自动下载项目依赖。
  • --yes:跳过命令行交互,直接使用默认配置。
npm install inquirer arg

编写命令行参数解析逻辑,在cli.js中添加:

import arg from 'arg';
// 解析命令行参数为 options
function parseArgumentsIntoOptions(rawArgs) {
    // 使用 arg 进行解析
    const args = arg({
        '--git': Boolean,
        '--yes': Boolean,
        '--install': Boolean,
        '-g': '--git',
        '-y': '--yes',
        '-i': '--install',
    }, {
        argv: rawArgs.slice(2),
    });
    return {
        skipPrompts: args['--yes'] || false,
        git: args['--git'] || false,
        template: args._[0],
        runInstall: args['--install'] || false,
    }
}
export function cli(args) {
    // 获取命令行配置
    let options = parseArgumentsIntoOptions(args);
    console.log(options);
}

实现使用默认配置和交互式配置选择逻辑,如下代码:

import arg from 'arg';
import inquirer from 'inquirer';

function parseArgumentsIntoOptions(rawArgs) {
    // ...
}
async function promptForMissingOptions(options) {
    // 默认使用名为 JavaScript 的模板
    const defaultTemplate = 'JavaScript';
    // 使用默认模板则直接返回
    if (options.skipPrompts) {
        return {...options,
            template: options.template || defaultTemplate,
        };
    }
    // 准备交互式问题 
    const questions = [];
    if (!options.template) {
        questions.push({
            type: 'list',
            name: 'template',
            message: 'Please choose which project template to use',
            choices: ['JavaScript', 'TypeScript'],
            default: defaultTemplate,
        });
    }
    if (!options.git) {
        questions.push({
            type: 'confirm',
            name: 'git',
            message: 'Initialize a git repository?',
            default: false,
        });
    }
    // 使用 inquirer 进行交互式查询,并获取用户答案选项
    const answers = await inquirer.prompt(questions);
    return {...options,
        template: options.template || answers.template,
        git: options.git || answers.git,
    };
}
export async function cli(args) {
    let options = parseArgumentsIntoOptions(args);
    options = await promptForMissingOptions(options);
    console.log(options);
}

下面我们需要完成下载模板到本地的逻辑,我们事先准备好两种名为typescriptjavascript的模板,并将相关的模板存储在项目的根目录中

我们使用ncp包实现跨平台递归拷贝文件,使用chalk做个性化输出。安装相关依赖如下:

npm install ncp chalk

src/目录下,创建新的文件main.js,代码如下:


import chalk from 'chalk';
import fs from 'fs';
import ncp from 'ncp';
import path from 'path';
import {
    promisify
}
from 'util';
const access = promisify(fs.access);
const copy = promisify(ncp);
// 递归拷贝文件
async function copyTemplateFiles(options) {
    return copy(options.templateDirectory, options.targetDirectory, {
        clobber: false,
    });
}
// 创建项目
export async function createProject(options) {
    options = {...options,
        targetDirectory: options.targetDirectory || process.cwd(),
    };
    const currentFileUrl = import.meta.url;
    const templateDir = path.resolve(new URL(currentFileUrl).pathname, '../../templates', options.template.toLowerCase());
    options.templateDirectory = templateDir;
    try {
        // 判断模板是否存在
        await access(templateDir, fs.constants.R_OK);
    } catch (err) {
        // 模板不存在 
        console.error('%s Invalid template name', chalk.red.bold('ERROR'));
        process.exit(1);
    }
    // 拷贝模板
    await copyTemplateFiles(options);
    console.log('%s Project ready', chalk.green.bold('DONE'));
    return true;
}

接下来,我们需要完成git的初始化以及依赖安装工作,这时候需要用到以下内容。

  • execa:允许开发中使用类似git的外部命令。

  • pkg-install:使用yarn installnpm install安装依赖。

  • listr:给出当前进度 progress。

npm install execa pkg-install listr

更新main.js

const { projectInstall } = require('pkg-install');
const { access } = require('fs/promises');
const chalk = require('chalk');
const fs = require('fs');
const path = require('path');
const execa = require('execa');
const Listr = require('listr');
const util = require('util');
const ncp = require('ncp');
const copy = util.promisify(ncp);

// 拷贝模板
async function copyTemplateFiles(options) {
  return copy(options.templateDirectory, options.targetDirectory, {
    clobber: false,
  });
}

// 初始化 git
async function initGit(options) {
  // 执行 git init
  const result = await execa('git', ['init'], {
    cwd: options.targetDirectory,
  });

  if (result.failed) {
    return Promise.reject(new Error('Failed to initialize git'));
  }
  return;
}

// 创建项目
export async function createProject(options) {
  options = {
    ...options,
    targetDirectory: options.targetDirectory || process.cwd()

  };

  const templateDir = path.resolve(
    __dirname,
    '../templates',
    options.template
  );

  options.templateDirectory = templateDir;

  try {
    console.log(templateDir);

    // 判断模板是否存在
    await access(templateDir, fs.constants.R_OK);
  } catch (err) {
    console.error('%s Invalid template name', chalk.red.bold('ERROR'));
    process.exit(1);
  }

  // 声明 tasks

  const tasks = new Listr([
    {
      title: 'Copy project files',
      task: () => copyTemplateFiles(options),
    },
    {
      title: 'Initialize git',
      task: () => initGit(options),
      enabled: () => options.git,
    },
    {
      title: 'Install dependencies',
      task: () =>
        projectInstall({
          cwd: options.targetDirectory,
        }),
      skip: () =>
        !options.runInstall
          ? 'Pass --install to automatically install dependencies'
          : undefined,
    },
  ]);

  // 并行执行 tasks
  await tasks.run();
  console.log('%s Project ready', chalk.green.bold('DONE'));
  return true;
}

总结

此时一个简单的脚手架已经完成,文件模板和cli命令根据实际需求自行配置扩展

源码地址

github

搭建一个项目脚手架或模型脚手架是软件开发和机器学习建模中常见的任务,目的是为后续的开发工作提供一个标准化、可扩展的基础框架。以下是针对不同场景的详细指南。 ### 3.1 软件开发中的项目脚手架 在软件开发中,项目脚手架通常包括模块划分、依赖管理、分层架构设计等内容。以下是一个典型的 Spring Boot 项目的脚手架搭建步骤: #### 模块划分 - **父工程(scaffold-parent)**:负责管理所有子模块的依赖版本和公共配置,确保统一性和一致性。 - **通用工具模块(scaffold-common)**:包含全局异常处理、工具类、Swagger 配置、Redis 模板、公共 DTO/枚举等通用功能。 - **网关模块(scaffold-gateway)**:实现路由转发、JWT 鉴权、限流、跨域处理等功能。 - **认证中心模块(scaffold-auth)**:负责用户登录、权限校验、RBAC 模型实现等安全相关功能。 - **业务服务模块(如 scaffold-user)**:具体业务逻辑的实现,例如用户管理、订单管理等。 - **前端模块(如 scaffold-admin-ui)**:后台管理系统的前端部分,通常使用 Vue 或 Ant Design Pro 等技术栈。 #### 分层架构设计 以 `scaffold-user` 模块为例,常见的分层架构包括: - **Controller 层**:负责接收 HTTP 请求并返回响应。 - **Service 层**:处理核心业务逻辑。 - **Repository 层**:与数据库交互,进行数据持久化操作。 - **DTO(Data Transfer Object)**:用于在不同层之间传递数据。 - **Entity**:对应数据库表的实体类。 #### 依赖管理 通过 Maven 或 Gradle 进行依赖管理,确保各个模块之间的依赖关系清晰且易于维护。父工程中定义公共依赖及其版本号,子模块只需引入所需的依赖即可。 ### 3.2 机器学习建模中的模型脚手架 在机器学习领域,模型脚手架搭建主要包括数据预处理、特征工程、模型训练、评估与部署等环节。以下是详细的步骤: #### 数据预处理 - **数据清洗**:去除缺失值、异常值,处理重复数据。 - **数据标准化**:对数据进行归一化或标准化处理,以便于模型训练。 - **数据分割**:将数据集划分为训练集、验证集和测试集。 #### 特征工程 - **特征选择**:选择对目标变量有显著影响的特征。 - **特征编码**:对分类变量进行独热编码或标签编码。 - **特征缩放**:对连续变量进行标准化或归一化。 #### 模型训练 - **选择算法**:根据问题类型(分类、回归、聚类等)选择合适的算法。 - **超参数调优**:通过网格搜索或随机搜索优化模型参数。 - **交叉验证**:使用 K 折交叉验证评估模型性能。 #### 模型评估 - **评估指标**:根据任务类型选择适当的评估指标,如准确率、召回率、F1 分数(分类),均方误差(回归)等。 - **可视化分析**:通过混淆矩阵、ROC 曲线、PR 曲线等工具直观展示模型性能。 #### 模型部署 - **模型保存**:将训练好的模型保存为文件格式(如 `.pkl` 或 `.h5`)。 - **API 接口**:使用 Flask 或 FastAPI 构建 RESTful API,对外提供模型预测服务。 - **容器化部署**:通过 Docker 容器化应用,便于部署和管理。 ### 3.3 示例代码 以下是一个简单的 Python 脚本,展示了如何使用 Scikit-learn 构建一个基本的机器学习模型脚手架: ```python import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score # 数据加载与预处理 data = pd.read_csv('data.csv') X = data.drop('target', axis=1) y = data['target'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) # 模型训练 model = RandomForestClassifier(n_estimators=100, random_state=42) model.fit(X_train, y_train) # 模型评估 y_pred = model.predict(X_test) accuracy = accuracy_score(y_test, y_pred) print(f"Model Accuracy: {accuracy:.2f}") ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值