JavaScript系列(90)--前端脚手架开发

news2025/2/27 16:10:34

前端脚手架开发 🛠️

前端脚手架是现代前端开发流程中的重要工具,它能够帮助开发者快速初始化项目结构、配置开发环境、设置构建流程,从而提高开发效率和标准化项目结构。本文将详细介绍前端脚手架的开发原理、实现方式以及最佳实践。

脚手架概述 🌟

💡 小知识:脚手架(Scaffold)源自建筑行业,指辅助建筑工人进行高空作业的临时平台。在软件开发中,脚手架指能够快速生成项目基础结构的工具,让开发者专注于业务逻辑而非繁琐的项目配置。

为什么需要脚手架

现代前端开发已经变得越来越复杂,一个典型的项目通常需要:

  • 模块化系统管理
  • 代码转译和编译
  • 开发服务器配置
  • 热更新支持
  • 测试框架集成
  • 代码格式化和检查
  • 构建和优化流程

手动设置这些配置既耗时又容易出错,而脚手架工具使得开发者可以通过简单的命令就能创建符合最佳实践的项目结构,极大地提高了开发效率。

脚手架的核心功能

一个完整的前端脚手架工具通常提供以下功能:

  1. 项目初始化 - 创建项目目录结构和基础文件
  2. 依赖管理 - 安装和配置项目依赖
  3. 开发环境 - 配置开发服务器、热重载等
  4. 构建流程 - 设置代码编译、打包和优化流程
  5. 项目拓展 - 提供插件机制或子生成器支持
  6. 开发规范 - 集成代码格式化、检查工具
  7. 文档生成 - 自动生成项目文档

脚手架原理与架构 📐

核心工作流程

1. 命令行解析 -> 确定用户意图
2. 项目配置 -> 收集用户输入或使用默认配置
3. 模板获取 -> 从本地或远程获取模板
4. 模板编译 -> 根据配置处理模板变量
5. 文件生成 -> 将编译后的模板写入目标目录
6. 依赖安装 -> 安装项目所需依赖包
7. 初始化操作 -> 执行项目初始化命令
8. 完成提示 -> 给出使用提示和下一步操作建议

脚手架架构设计

一个典型的脚手架工具包含以下主要组件:

  1. 命令行接口 (CLI)

    • 解析命令行参数
    • 展示用户交互界面
    • 调用相应的子命令
  2. 配置管理器

    • 收集用户配置
    • 管理默认配置
    • 配置校验与合并
  3. 模板引擎

    • 加载模板文件
    • 编译模板内容
    • 处理条件渲染逻辑
  4. 文件操作模块

    • 创建项目目录结构
    • 写入生成的文件
    • 复制静态资源
  5. 包管理器接口

    • 调用npm/yarn/pnpm等包管理器
    • 安装项目依赖
    • 处理安装错误

数据流图

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   用户输入   │───>│  配置收集   │───>│  模板处理   │
└─────────────┘    └─────────────┘    └─────────────┘
                        │                   │
                        │                   ▼
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│ 项目初始化  │<───│  依赖安装   │<───│  文件生成   │
└─────────────┘    └─────────────┘    └─────────────┘

命令行工具实现

使用Node.js创建脚手架CLI的核心代码示例:

// cli.js
#!/usr/bin/env node
const program = require('commander');
const chalk = require('chalk');
const create = require('./commands/create');

program
    .version('1.0.0')
    .description('A modern frontend scaffold tool');

program
    .command('create <project-name>')
    .description('Create a new project')
    .option('-t, --template <template>', 'Project template to use')
    .option('--typescript', 'Use TypeScript')
    .option('--skip-install', 'Skip installing dependencies')
    .action((name, options) => {
        console.log(chalk.blue(`Creating project: ${name}`));
        create(name, options);
    });

program.parse(process.argv);

if (!process.argv.slice(2).length) {
    program.outputHelp();
}

交互式配置收集

使用inquirer.js实现用户交互体验:

// questions.js
const inquirer = require('inquirer');

async function promptForProjectInfo() {
    return inquirer.prompt([
        {
            type: 'input',
            name: 'projectName',
            message: 'Project name:',
            default: 'my-app'
        },
        {
            type: 'list',
            name: 'framework',
            message: 'Select a framework:',
            choices: ['React', 'Vue', 'Angular', 'None'],
            default: 'React'
        },
        {
            type: 'checkbox',
            name: 'features',
            message: 'Select additional features:',
            choices: [
                { name: 'TypeScript', value: 'typescript' },
                { name: 'ESLint', value: 'eslint' },
                { name: 'Jest', value: 'jest' },
                { name: 'Prettier', value: 'prettier' }
            ]
        },
        {
            type: 'list',
            name: 'packageManager',
            message: 'Select a package manager:',
            choices: ['npm', 'yarn', 'pnpm'],
            default: 'npm'
        }
    ]);
}

module.exports = { promptForProjectInfo };

模板管理与渲染 📄

模板组织结构

一个标准的脚手架模板结构:

template-react/                # React模板
├── template/                  # 模板文件
│   ├── public/                # 静态资源
│   │   ├── components/        # 组件目录
│   │   ├── App.js             # 应用入口
│   │   └── index.js           # 主入口
│   ├── package.json           # 项目配置
│   └── README.md              # 项目说明
└── config.js                  # 模板配置

模板配置示例

// config.js
module.exports = {
    name: 'react-template',
    description: 'React project template with modern configuration',
    version: '1.0.0',
    prompts: [
        {
            type: 'confirm',
            name: 'useRouter',
            message: 'Add React Router?',
            default: false
        },
        {
            type: 'list',
            name: 'stateManagement',
            message: 'Choose state management solution:',
            choices: ['None', 'Redux', 'MobX', 'Context API'],
            default: 'None'
        }
    ],
    filters: {
        'src/redux/**/*': 'stateManagement === "Redux"',
        'src/mobx/**/*': 'stateManagement === "MobX"',
        'src/router/**/*': 'useRouter'
    },
    complete: (data, { chalk }) => {
        console.log(chalk.green('Project created successfully!'));
        console.log('To get started:');
        console.log(`cd ${data.projectName}`);
        console.log(`${data.packageManager} start`);
    }
};

模板引擎实现

使用EJS作为模板引擎处理文件:

// template-engine.js
const ejs = require('ejs');
const fs = require('fs-extra');
const path = require('path');
const glob = require('glob');

async function renderTemplates(src, dest, data) {
    const templates = glob.sync('**/*', {
        cwd: src,
        nodir: true,
        dot: true
    });
    
    for (const file of templates) {
        const sourcePath = path.join(src, file);
        const content = fs.readFileSync(sourcePath, 'utf-8');
        
        // 处理EJS模板
        let result;
        let targetFile = file;
        if (file.endsWith('.ejs')) {
            result = ejs.render(content, data);
            // 移除.ejs扩展名
            targetFile = file.slice(0, -4);
        } else {
            result = content;
        }
        
        const targetPath = path.join(dest, targetFile);
        
        // 确保目标目录存在
        await fs.ensureDir(path.dirname(targetPath));
        
        // 写入处理后的内容
        await fs.writeFile(targetPath, result);
    }
}

module.exports = { renderTemplates };

条件文件处理

根据用户配置决定是否包含特定文件:

// generate-project.js
const { evaluate } = require('./utils');

function shouldIncludeFile(file, filters, data) {
    if (!filters) return true;
    
    // 检查文件是否有条件过滤规则
    for (const pattern in filters) {
        if (minimatch(file, pattern)) {
            // 计算条件表达式
            return evaluate(filters[pattern], data);
        }
    }
    
    return true;
}

async function generateProject(template, dest, data, filters) {
    const files = glob.sync('**/*', {
        cwd: template,
        nodir: true,
        dot: true
    });
    
    for (const file of files) {
        // 检查文件是否应该包含
        if (!shouldIncludeFile(file, filters, data)) {
            continue;
        }
        
        // 处理并写入文件
        // ...处理模板和复制文件逻辑
    }
}

动态模板变量处理

package.json模板示例:

{
  "name": "<%= projectName %>",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1"<% if (useRouter) { %>,
    "react-router-dom": "^6.10.0"<% } %>
    <% if (stateManagement === 'Redux') { %>,
    "redux": "^4.2.1",
    "react-redux": "^8.0.5"<% } %>
    <% if (stateManagement === 'MobX') { %>,
    "mobx": "^6.9.0",
    "mobx-react-lite": "^3.4.3"<% } %>
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }<% if (typescript) { %>,
  "devDependencies": {
    "typescript": "^4.9.5",
    "@types/react": "^18.0.28",
    "@types/react-dom": "^18.0.11"<% if (useRouter) { %>,
    "@types/react-router-dom": "^5.3.3"<% } %>
  }<% } %>
}

脚手架工具实现 ⚙️

创建项目命令实现

核心实现代码:

// commands/create.js
const path = require('path');
const fs = require('fs-extra');
const chalk = require('chalk');
const { promptForProjectInfo } = require('../utils/questions');
const { renderTemplates } = require('../utils/template-engine');
const { installDependencies } = require('../utils/package-manager');
const { getTemplate } = require('../utils/template-loader');

async function create(projectName, options) {
    try {
        // 1. 项目目标路径
        const targetDir = path.resolve(process.cwd(), projectName);
        
        // 2. 检查目录是否已存在
        if (fs.existsSync(targetDir)) {
            const { overwrite } = await inquirer.prompt([{
                type: 'confirm',
                name: 'overwrite',
                message: `Directory ${projectName} already exists. Overwrite?`,
                default: false
            }]);
            
            if (!overwrite) {
                console.log(chalk.red('Operation cancelled'));
                return;
            }
            
            await fs.remove(targetDir);
        }
        
        // 3. 收集用户配置
        const userAnswers = await promptForProjectInfo();
        const config = {
            ...userAnswers,
            projectName,
            ...options
        };
        
        // 4. 加载模板
        const template = await getTemplate(config.framework.toLowerCase());
        
        // 5. 渲染模板
        await fs.ensureDir(targetDir);
        await renderTemplates(
            path.join(template.path, 'template'),
            targetDir,
            config
        );
        
        // 6. 安装依赖
        if (!options.skipInstall) {
            console.log();
            console.log(chalk.cyan('Installing dependencies...'));
            await installDependencies(targetDir, config.packageManager);
        }
        
        // 7. 完成信息
        console.log();
        console.log(chalk.green('✨ Project creation complete!'));
        console.log();
        console.log('To get started:');
        console.log(`  cd ${projectName}`);
        if (options.skipInstall) {
            console.log(`  ${config.packageManager} install`);
        }
        console.log(`  ${config.packageManager} start`);
        
        // 8. 运行模板自定义的完成函数
        if (template.config.complete) {
            template.config.complete(config, { chalk });
        }
        
    } catch (error) {
        console.error(chalk.red('Error creating project:'), error);
        process.exit(1);
    }
}

module.exports = create;

依赖安装实现

// utils/package-manager.js
const execa = require('execa');
const ora = require('ora');

async function installDependencies(targetDir, packageManager = 'npm') {
    const spinner = ora('Installing dependencies...').start();
    
    try {
        const command = packageManager;
        const args = ['install'];
        
        // 根据不同的包管理器调整参数
        if (packageManager === 'yarn') {
            // yarn默认安装,不需要特别参数
        } else if (packageManager === 'pnpm') {
            // pnpm可能需要额外参数
        }
        
        await execa(command, args, {
            cwd: targetDir,
            stdio: 'pipe' // 隐藏标准输出
        });
        
        spinner.succeed('Dependencies installed successfully');
        return true;
    } catch (error) {
        spinner.fail('Failed to install dependencies');
        console.error(`\n${error.message}`);
        return false;
    }
}

module.exports = { installDependencies };

模板获取实现

// utils/template-loader.js
const path = require('path');
const fs = require('fs-extra');
const os = require('os');
const { downloadFromGitHub } = require('./downloader');

// 模板缓存目录
const TEMPLATE_CACHE_DIR = path.join(os.homedir(), '.my-scaffold', 'templates');

/**
 * 获取项目模板
 * @param {string} templateName 模板名称
 * @returns {Promise<Object>} 模板信息
 */
async function getTemplate(templateName) {
    // 确保缓存目录存在
    await fs.ensureDir(TEMPLATE_CACHE_DIR);
    
    const templateMap = {
        'react': 'my-org/react-template',
        'vue': 'my-org/vue-template',
        'angular': 'my-org/angular-template'
    };
    
    // 获取模板完整名称
    const repoName = templateMap[templateName];
    if (!repoName) {
        throw new Error(`Template ${templateName} not found`);
    }
    
    // 检查本地缓存
    const templateDir = path.join(TEMPLATE_CACHE_DIR, templateName);
    const isTemplateExist = await fs.pathExists(templateDir);
    
    if (!isTemplateExist) {
        // 下载模板
        await downloadFromGitHub(repoName, templateDir);
    }
    
    // 加载模板配置
    const configPath = path.join(templateDir, 'config.js');
    const config = require(configPath);
    
    return {
        path: templateDir,
        config
    };
}

module.exports = { getTemplate };

脚手架开发实例 🚀

创建自己的脚手架生成器

// 创建脚手架项目的引导程序
#!/usr/bin/env node
const inquirer = require('inquirer');
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
const { execSync } = require('child_process');

async function init() {
    console.log(chalk.blue('欢迎使用脚手架生成器!'));
    console.log('这个工具将帮助你创建你自己的前端脚手架工具.');
    console.log();
    
    const answers = await inquirer.prompt([
        {
            type: 'input',
            name: 'name',
            message: '脚手架名称:',
            default: 'my-scaffold'
        },
        {
            type: 'input',
            name: 'description',
            message: '简短描述:',
            default: 'A modern frontend scaffold tool'
        },
        {
            type: 'list',
            name: 'templateEngine',
            message: '选择模板引擎:',
            choices: ['EJS', 'Handlebars', 'Nunjucks'],
            default: 'EJS'
        },
        {
            type: 'confirm',
            name: 'includeExamples',
            message: '包含示例模板?',
            default: true
        }
    ]);
    
    const targetDir = path.resolve(process.cwd(), answers.name);
    
    // 检查目录是否存在
    if (fs.existsSync(targetDir)) {
        const { overwrite } = await inquirer.prompt([{
            type: 'confirm',
            name: 'overwrite',
            message: `目录 ${answers.name} 已存在. 覆盖?`,
            default: false
        }]);
        
        if (!overwrite) {
            console.log(chalk.red('操作已取消'));
            return;
        }
        
        await fs.remove(targetDir);
    }
    
    // 创建项目结构
    await createProjectStructure(targetDir, answers);
    
    console.log();
    console.log(chalk.green('✨ 脚手架项目创建成功!'));
    console.log();
    console.log('接下来:');
    console.log(`  cd ${answers.name}`);
    console.log('  npm install');
    console.log('  npm link');
    console.log();
    console.log(`然后你可以运行 "${answers.name} create my-app" 来测试你的脚手架`);
}

// 省略createProjectStructure函数实现...

init().catch(err => {
    console.error(err);
    process.exit(1);
});

流行脚手架工具解析 🔍

Create React App

特点与功能

  • 零配置开箱即用
  • 集成开发服务器、编译器、测试工具
  • 支持TypeScript和PWA
  • 提供开发和生产环境优化

使用方式

# 创建新应用
npx create-react-app my-app

# 使用TypeScript
npx create-react-app my-app --template typescript

# 自定义模板
npx create-react-app my-app --template cra-template-custom

架构特点

  • 基于react-scripts实现构建和开发功能
  • 利用模板注入项目结构
  • 隐藏复杂配置,提供简单API

Vue CLI

特点与功能

  • 交互式项目创建
  • 插件化架构
  • 图形用户界面
  • 配置灵活可扩展
  • 支持预设配置

使用方式

# 安装
npm install -g @vue/cli

# 创建项目
vue create my-project

# 使用图形界面
vue ui

# 使用预设
vue create --preset username/repo my-project

架构特点

  • 基于插件系统和webpack配置
  • 允许通过插件扩展功能
  • 提供完整的GUI界面支持

Yeoman

特点与功能

  • 丰富的生成器生态
  • 高度可定制
  • 框架无关
  • 支持子生成器

使用方式

# 安装
npm install -g yo

# 安装生成器
npm install -g generator-webapp

# 运行生成器
yo webapp

# 运行子生成器
yo webapp:component

架构特点

  • 基于生成器系统
  • 每个生成器是一个独立的npm包
  • 高度可扩展的架构

主流脚手架比较

特性Create React AppVue CLIYeoman
配置灵活性低 (隐藏配置)高 (可插件化配置)高 (完全自定义)
易用性高 (零配置)中 (交互式配置)低 (需要选择生成器)
可扩展性低 (需要eject)高 (插件系统)高 (完全可定制)
生态规模单一目标 (React)中等 (Vue生态)大 (框架无关)
维护方式Facebook团队Vue.js核心团队社区维护

自定义脚手架开发实战 💻

Yeoman生成器开发

基本结构

generator-myapp/
├── generators/                # 生成器目录
│   ├── app/                   # 默认生成器
│   │   ├── index.js           # 生成器主文件
│   │   └── templates/         # 模板文件
│   └── component/             # 子生成器
│       ├── index.js           # 组件生成器
│       └── templates/         # 组件模板
├── package.json               # 包配置
└── README.md                  # 说明文档

生成器实现示例

// generators/app/index.js
const Generator = require('yeoman-generator');
const chalk = require('chalk');
const yosay = require('yosay');

module.exports = class extends Generator {
    // 构造函数
    constructor(args, opts) {
        super(args, opts);
        
        // 添加选项
        this.option('typescript', {
            type: Boolean,
            default: false,
            description: 'Use TypeScript'
        });
    }
    
    // 初始化
    initializing() {
        this.log(yosay(
            `Welcome to the ${chalk.red('My App')} generator!`
        ));
    }
    
    // 获取用户输入
    async prompting() {
        this.answers = await this.prompt([
            {
                type: 'input',
                name: 'name',
                message: 'Your project name',
                default: this.appname // 默认为当前文件夹名
            },
            {
                type: 'list',
                name: 'cssPreprocessor',
                message: 'Which CSS preprocessor would you like to use?',
                choices: ['None', 'Sass', 'Less', 'Stylus'],
                default: 'Sass'
            },
            {
                type: 'checkbox',
                name: 'features',
                message: 'Select additional features:',
                choices: [
                    {
                        name: 'ESLint',
                        value: 'eslint',
                        checked: true
                    },
                    {
                        name: 'Jest',
                        value: 'jest',
                        checked: true
                    },
                    {
                        name: 'Prettier',
                        value: 'prettier',
                        checked: true
                    }
                ]
            }
        ]);
    }
    
    // 配置项目
    configuring() {
        // 创建.yo-rc.json配置文件
        this.config.set('cssPreprocessor', this.answers.cssPreprocessor);
        this.config.set('features', this.answers.features);
        this.config.set('typescript', this.options.typescript);
        this.config.save();
        
        // 如果使用ESLint,创建配置文件
        if (this.answers.features.includes('eslint')) {
            this.fs.copy(
                this.templatePath('.eslintrc.js'),
                this.destinationPath('.eslintrc.js')
            );
        }
    }
    
    // 写入文件
    writing() {
        // 复制静态文件
        this.fs.copy(
            this.templatePath('public/**/*'),
            this.destinationPath('public/')
        );
        
        // 处理package.json
        this.fs.copyTpl(
            this.templatePath('package.json'),
            this.destinationPath('package.json'),
            {
                name: this.answers.name,
                typescript: this.options.typescript,
                eslint: this.answers.features.includes('eslint'),
                jest: this.answers.features.includes('jest'),
                prettier: this.answers.features.includes('prettier'),
                cssPreprocessor: this.answers.cssPreprocessor.toLowerCase()
            }
        );
        
        // 处理README
        this.fs.copyTpl(
            this.templatePath('README.md'),
            this.destinationPath('README.md'),
            { name: this.answers.name }
        );
        
        // 源代码目录
        const srcDir = 'src';
        
        // 选择正确的扩展名
        const ext = this.options.typescript ? 'tsx' : 'jsx';
        const styleExt = this.getStyleExtension();
        
        // 复制并处理主要源文件
        this.fs.copyTpl(
            this.templatePath(`src/App.${ext}`),
            this.destinationPath(`${srcDir}/App.${ext}`),
            { 
                name: this.answers.name,
                styleExt
            }
        );
        
        // 复制样式文件
        this.fs.copy(
            this.templatePath(`src/App.${styleExt}`),
            this.destinationPath(`${srcDir}/App.${styleExt}`)
        );
    }
    
    // 安装依赖
    install() {
        this.installDependencies();
    }
    
    // 结束
    end() {
        this.log(chalk.green('Done! Happy coding!'));
    }
    
    // 辅助方法
    getStyleExtension() {
        const cssMap = {
            'Sass': 'scss',
            'Less': 'less',
            'Stylus': 'styl',
            'None': 'css'
        };
        return cssMap[this.answers.cssPreprocessor];
    }
};

脚手架最佳实践 ⭐

设计原则

  1. 简单性优先 - 脚手架应该易于使用,不应要求开发者了解太多底层细节
  2. 渐进式定制 - 提供合理默认值,但允许高级用户进行定制
  3. 一致的用户体验 - 命令行界面和交互应保持一致
  4. 适当的提示 - 提供清晰的错误提示和操作指南
  5. 可扩展架构 - 设计可扩展的模块化结构
  6. 良好文档 - 提供完整的使用说明和API文档

开发建议

  1. 模板版本控制 - 为模板设置版本管理,确保兼容性
  2. 提供多模板支持 - 支持多种项目类型和框架
  3. 设计人性化CLI - 提供帮助信息、彩色输出、进度指示器等增强体验
  4. 用户配置持久化 - 保存用户首选项以简化重复操作
  5. 模块化代码 - 分离关注点,使代码易于维护
  6. 缓存优化 - 缓存模板和依赖以提高性能
  7. 错误处理策略 - 优雅处理错误并提供恢复选项

测试策略

  1. 单元测试核心功能
  2. 集成测试确保组件协同工作
  3. 端到端测试验证完整工作流
  4. 快照测试确保生成文件的一致性
  5. 用户测试获取实际反馈

发布和维护

  1. 语义化版本控制
  2. 自动化发布流程
  3. 变更日志维护
  4. 兼容性策略
  5. 社区反馈收集机制

结语 📝

前端脚手架开发是前端工程化的重要一环,一个优秀的脚手架工具可以大幅提高团队效率,确保项目结构的一致性,并帮助新成员快速上手。通过本文,我们学习了:

  1. 脚手架的基本原理和架构设计
  2. 模板管理和渲染的核心实现
  3. 命令行工具和用户交互的实现方法
  4. 主流脚手架工具的特点和比较
  5. 自定义脚手架的开发实践和最佳实践

💡 学习建议:

  1. 从使用现有脚手架工具开始,理解其工作原理
  2. 尝试开发小型脚手架,解决特定团队需求
  3. 学习命令行工具开发和模板引擎的使用
  4. 了解不同脚手架的优缺点,借鉴其设计思想
  5. 持续改进和优化,根据用户反馈调整

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306960.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Python+django+mysql旅游数据爬虫采集可视化分析推荐系统

2024旅游推荐系统爬虫可视化&#xff08;协同过滤算法&#xff09; 基于Pythondjangomysql旅游数据爬虫采集可视化分析推荐系统 有文档说明 部署文档 视频讲解 ✅️基于用户的协同过滤推荐算法 卖价就是标价~ 项目技术栈 Python语言、Django框架、MySQL数据库、requests网络爬虫…

Oracle 12c Docker安装问题排查 sga_target 1536M is too small

一、问题描述 在虚拟机环境&#xff08;4核16GB内存&#xff09;上部署 truevoly/oracle-12c 容器镜像时&#xff0c;一切运行正常。然而&#xff0c;当在一台 128 核 CPU 和 512GB 内存的物理服务器上运行时&#xff0c;容器启动时出现了 ORA-00821 等错误&#xff0c;提示 S…

es-head(es库-谷歌浏览器插件)

1.下载es-head插件压缩包&#xff0c;并解压缩 2.谷歌浏览器添加插件 3.使用

Linux网络基础(协议 TCP/IP 网络传输基本流程 IP VS Mac Socket编程UDP)

文章目录 一.前言二.协议协议分层分层的好处 OSI七层模型TCP/IP五层(或四层)模型为什么要有TCP/IP协议TCP/IP协议与操作系统的关系(宏观上是如何实现的)什么是协议 三.网络传输基本流程局域网(以太网为例)通信原理MAC地址令牌环网 封装与解包分用 四.IP地址IP VS Mac地址 五.So…

Web开发:ORM框架之使用Freesql的导航属性

一、什么时候用导航属性 看数据库表的对应关系&#xff0c;一对多的时候用比较好&#xff0c;不用多写一个联表实体&#xff0c;而且查询高效 二、为实体配置导航属性 1.给关系是一的父表实体加上&#xff1a; [FreeSql.DataAnnotations.Navigate(nameof(子表.子表关联字段))]…

NLP07-朴素贝叶斯问句分类之数据集加载(1/3)

一、概述 数据集加载&#xff08;Dataset Loading&#xff09;是机器学习、自然语言处理&#xff08;NLP&#xff09;等领域中的一个重要步骤&#xff0c;指的是将外部数据&#xff08;如文件、数据库、网络接口等&#xff09;加载到程序中&#xff0c;以便进行后续处理、分析…

Rk3568驱动开发_点亮led灯(手动挡)_5

1.MMU简介 完成虚拟空间到物理空间的映射 内存保护设立存储器的访问权限&#xff0c;设置虚拟存储空间的缓冲特性 stm32点灯可以直接操作寄存器&#xff0c;但是linux点灯不能直接访问寄存器&#xff0c;linux会使能mmu linux中操作的都是虚拟地址&#xff0c;要想访问物理地…

LangChain构建行业知识库实践:从架构设计到生产部署全指南

文章目录 引言:行业知识库的进化挑战一、系统架构设计1.1 核心组件拓扑1.2 模块化设计原则二、关键技术实现2.1 文档预处理流水线2.2 混合检索增强三、领域适配优化3.1 医学知识图谱融合3.2 检索结果重排序算法四、生产环境部署4.1 性能优化方案4.2 安全防护体系五、评估与调优…

Vscode编辑器:解读文件结构、插件的导入导出、常用快捷键配置技巧及其常见问题的解决方案

一、文件与文件夹结构 1.文件结构 文件名作用.babelrc配置 Babel 编译选项&#xff0c;指定代码转译规则。.editorconfig定义项目代码格式规范&#xff0c;如缩进风格和空格数量等。.eslintignore列出 ESLint 忽略的文件或文件夹。.eslintrc.js配置 ESLint 的规则和插件。.gi…

线性回归 (Linear Regression)案例分析1

广告费用与产品销量 工欲善其事必先利其器数据分析1. 检查缺失值、异常值3. 散点图查看特征、响应相关性3. 热力图查看特征、响应相关性 特征工程1、导入必要工具包2、读取数据3、数据标准化4、保存特征工程的结果到文件&#xff0c;供机器学习模型使用 模型选择读取数据数据准…

uni-app集成sqlite

Sqlite SQLite 是一种轻量级的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛应用于各种应用程序中&#xff0c;特别是那些需要嵌入式数据库解决方案的场景。它不需要单独的服务器进程或系统配置&#xff0c;所有数据都存储在一个单一的普通磁盘文件中&am…

【HTML— 快速入门】HTML 基础

准备工作 vscode下载 百度网盘 Subline Text 下载 Sublime Text下载 百度网盘 vscode 下载 Sublime Text 是一款轻量好用的文本编辑器&#xff0c;我们在写前端代码时&#xff0c;使用 Sublime Text 打开比使用记事本打开&#xff0c;得到的代码体验更好&#xff0c;比 vscode…

【MATLAB中的图像数据结构】

MATLAB中的图像数据结构 目录 MATLAB中的图像数据结构目标 &#xff1a;知识点 &#xff1a;1. 图像的存储方式 &#xff1a;2. 图像的颜色空间 &#xff1a;3. 图像的像素操作 &#xff1a; 示例代码 &#xff1a;1. 读取和显示图像 &#xff1a;2. 查看图像信息 &#xff1a;…

在线抽奖系统——项目介绍

目录 项目介绍 页面预览 需求分析 管理员登录注册 人员模块 奖品模块 活动模块 抽奖模块 系统设计 系统架构 项目环境 数据库设计 安全设计 完整代码&#xff1a;项目完整代码/在线抽奖系统/lottery-system Echo/project - 码云 - 开源中国 项目介绍 利用 MySQ…

JavaScript 系列之:Ajax、Promise、Axios

前言 同步&#xff1a;会阻塞。同步代码按照编写的顺序逐行依次执行&#xff0c;只有当前的任务完成后&#xff0c;才会执行下一个任务。 异步&#xff1a;异步代码不会阻塞后续代码的执行。当遇到异步操作时&#xff0c;JavaScript 会将该操作放入任务队列中&#xff0c;继续…

鸿蒙开发深入浅出01(基本环境搭建、页面模板与TabBar)

鸿蒙开发深入浅出01&#xff08;基本环境搭建、页面模板与TabBar&#xff09; 1、效果展示2、下载 DevEco Studio3、创建项目4、新建页面模板5、更改应用信息6、新建以下页面7、Index.ets8、真机运行9、图片资源文件 1、效果展示 2、下载 DevEco Studio 访问官网根据自己的版本…

FreeRTOS动态任务和静态任务创建

一.动态任务创建 1.搭建任务框架 去task.c中将任务参数复制到main中 然后将const去掉&#xff0c;它会限制参数类型&#xff0c;任务大小、任务优先级、任务句柄需要去宏定义&#xff0c;任务句柄是指针类型要取地址 vTaskStartScheduler(); //开启任务调度&#xff0c;.c…

QT:Graphics View的坐标系介绍

在 Qt 的 Graphics View 框架中&#xff0c;存在三种不同的坐标系&#xff0c;分别是 物品坐标系&#xff08;Item Coordinates&#xff09;、场景坐标系&#xff08;Scene Coordinates&#xff09; 和 视图坐标系&#xff08;View Coordinates&#xff09;。这三种坐标系在图形…

C# httpclient 和 Flurl.Http 的测试

关于C#调用接口或Post,Flurl封装了httpclient, CSDN有哥们提供了一个公网的测试网站&#xff0c;可以测试Post调用&#xff0c;我写了2个函数&#xff0c;测试httpclient和Flurl使用Post: async 和 await 是成对使用的&#xff0c;为了接受web异步返回的数据&#xff0c;winfor…

精选案例展 | 智己汽车—全栈可观测驱动智能化运营与成本优化

本案例为“观测先锋 2024 可观测平台创新应用案例大赛”精选案例&#xff0c;同时荣获IT168“2024技术卓越奖评选-年度创新解决方案”奖。 项目背景 近年来&#xff0c;中国汽车行业进入转型升级阶段&#xff0c;智能网联技术成为行业发展的核心。车联网、自动驾驶等技术的加速…