create-vue 生成式脚手架源码解析

文章目录

  • 命令交互
    • 输出渐变标题
    • 解析命令行参数
    • 命令行交互
      • 国际化提示
      • prompts 库实现命令行交互
  • 生成模版
    • 创建项目输出文件夹
    • 生成 packge.json
    • 查找预设的模版文件
    • 根据路径生成模块文件
    • render 生成模版
    • 填充 ejs 模版数据
    • 根据生成项目是 ts 还是 js 后置处理
    • 根据需要的模块生成所有对应的 README.md 文件
  • 结尾提示

命令交互

输出渐变标题

async function init() {// process.stdout.isTTY 是否在终端运行// process.stdout.getColorDepth() 支持的颜色数量console.log(process.stdout.isTTY && process.stdout.getColorDepth() > 8? // banners.gradientBanner 彩色文字banners.gradientBanner: banners.defaultBanner)...
}

banners

const defaultBanner = 'Vue.js - The Progressive JavaScript Framework'// generated by the following code:
//
// require('gradient-string')([
//   { color: '#42d392', pos: 0 },
//   { color: '#42d392', pos: 0.1 },
//   { color: '#647eff', pos: 1 }
// ])('Vue.js - The Progressive JavaScript Framework'))
//
// Use the output directly here to keep the bundle small.
const gradientBanner ='\x1B[38;2;66;211;146mV\x1B[39m\x1B[38;2;66;211;146mu\x1B[39m\x1B[38;2;66;211;146me\x1B[39m\x1B[38;2;66;211;146m.\x1B[39m\x1B[38;2;66;211;146mj\x1B[39m\x1B[38;2;67;209;149ms\x1B[39m \x1B[38;2;68;206;152m-\x1B[39m \x1B[38;2;69;204;155mT\x1B[39m\x1B[38;2;70;201;158mh\x1B[39m\x1B[38;2;71;199;162me\x1B[39m \x1B[38;2;72;196;165mP\x1B[39m\x1B[38;2;73;194;168mr\x1B[39m\x1B[38;2;74;192;171mo\x1B[39m\x1B[38;2;75;189;174mg\x1B[39m\x1B[38;2;76;187;177mr\x1B[39m\x1B[38;2;77;184;180me\x1B[39m\x1B[38;2;78;182;183ms\x1B[39m\x1B[38;2;79;179;186ms\x1B[39m\x1B[38;2;80;177;190mi\x1B[39m\x1B[38;2;81;175;193mv\x1B[39m\x1B[38;2;82;172;196me\x1B[39m \x1B[38;2;83;170;199mJ\x1B[39m\x1B[38;2;83;167;202ma\x1B[39m\x1B[38;2;84;165;205mv\x1B[39m\x1B[38;2;85;162;208ma\x1B[39m\x1B[38;2;86;160;211mS\x1B[39m\x1B[38;2;87;158;215mc\x1B[39m\x1B[38;2;88;155;218mr\x1B[39m\x1B[38;2;89;153;221mi\x1B[39m\x1B[38;2;90;150;224mp\x1B[39m\x1B[38;2;91;148;227mt\x1B[39m \x1B[38;2;92;145;230mF\x1B[39m\x1B[38;2;93;143;233mr\x1B[39m\x1B[38;2;94;141;236ma\x1B[39m\x1B[38;2;95;138;239mm\x1B[39m\x1B[38;2;96;136;243me\x1B[39m\x1B[38;2;97;133;246mw\x1B[39m\x1B[38;2;98;131;249mo\x1B[39m\x1B[38;2;99;128;252mr\x1B[39m\x1B[38;2;100;126;255mk\x1B[39m'export { defaultBanner, gradientBanner }

解析命令行参数

async function init() {const cwd = process.cwd()// possible options:// --default// --typescript / --ts// --jsx// --router / --vue-router// --pinia// --with-tests / --tests (equals to `--vitest --cypress`)// --vitest// --cypress// --nightwatch// --playwright// --eslint// --eslint-with-prettier (only support prettier through eslint for simplicity)// --force (for force overwriting)// 解析命令行参数const argv = minimist(process.argv.slice(2), {alias: {typescript: ['ts'], // 别名映射, typescript 还会被映射成 ts'with-tests': ['tests'],router: ['vue-router']},string: ['_'],// all arguments are treated as booleansboolean: true})// if any of the feature flags is set, we would skip the feature prompts// 是否命令行传入了参数,传入了则跳过后续交互式选择const isFeatureFlagsUsed =typeof (argv.default ??argv.ts ??argv.jsx ??argv.router ??argv.pinia ??argv.tests ??argv.vitest ??argv.cypress ??argv.nightwatch ??argv.playwright ??argv.eslint) === 'boolean'// 获取创建的文件名let targetDir = argv._[0]console.log('@targetDir', targetDir)const defaultProjectName = !targetDir ? 'vue-project' : targetDirconst forceOverwrite = argv.force}

命令行交互

国际化提示

  // 根据用户时区语言,拿到对应的预设国际化内容 (locales文件夹下)const language = getLanguage()
// 返回用户语言
function getLocale() {const shellLocale =Intl.DateTimeFormat().resolvedOptions().locale || // Built-in ECMA-402 supportprocess.env.LC_ALL || // POSIX locale environment variablesprocess.env.LC_MESSAGES ||process.env.LANG ||// TODO: Windows support if needed, could consider https://www.npmjs.com/package/os-locale'en-US' // Default fallbackconst locale = shellLocale.split('.')[0].replace('_', '-')return locale
}
// 拿到国际化文件内容
export default function getLanguage() {const locale = getLocale()// Note here __dirname would not be transpiled,// so it refers to the __dirname of the file `<repositoryRoot>/outfile.cjs`// TODO: use glob import once https://github.com/evanw/esbuild/issues/3320 is fixedconst localesRoot = path.resolve(__dirname, 'locales')const languageFilePath = path.resolve(localesRoot, `${locale}.json`)const doesLanguageExist = fs.existsSync(languageFilePath)if (!doesLanguageExist) {console.warn(`\x1B[33mThe locale langage "${locale}" is not supported, fallback to "en-US".\n\x1B[39m`)}const lang: Language = doesLanguageExist? require(languageFilePath): require(path.resolve(localesRoot, 'en-US.json'))return lang
}
  • 国际化配置文件如下所示
    在这里插入图片描述

prompts 库实现命令行交互

let result: {projectName?: stringshouldOverwrite?: booleanpackageName?: stringneedsTypeScript?: booleanneedsJsx?: booleanneedsRouter?: booleanneedsPinia?: booleanneedsVitest?: booleanneedsE2eTesting?: false | 'cypress' | 'nightwatch' | 'playwright'needsEslint?: booleanneedsPrettier?: boolean} = {}try {// Prompts:// - Project name://   - whether to overwrite the existing directory or not?//   - enter a valid package name for package.json// - Project language: JavaScript / TypeScript// - Add JSX Support?// - Install Vue Router for SPA development?// - Install Pinia for state management?// - Add Cypress for testing?// - Add Nightwatch for testing?// - Add Playwright for end-to-end testing?// - Add ESLint for code quality?// - Add Prettier for code formatting?console.log('@target', targetDir)result = await prompts([{name: 'projectName',type: targetDir ? null : 'text',message: language.projectName.message,initial: defaultProjectName,onState: (state) => (targetDir = String(state.value).trim() || defaultProjectName)},{name: 'shouldOverwrite',type: () => (canSkipEmptying(targetDir) || forceOverwrite ? null : 'toggle'),message: () => {const dirForPrompt =targetDir === '.'? language.shouldOverwrite.dirForPrompts.current: `${language.shouldOverwrite.dirForPrompts.target} "${targetDir}"`return `${dirForPrompt} ${language.shouldOverwrite.message}`},initial: true,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive},{name: 'overwriteChecker',type: (prev, values) => {if (values.shouldOverwrite === false) {throw new Error(red('✖') + ` ${language.errors.operationCancelled}`)}return null}},{name: 'packageName', //输入package.json包名,默认和项目名 targetDir 一致type: () => (isValidPackageName(targetDir) ? null : 'text'),message: language.packageName.message,initial: () => toValidPackageName(targetDir), // 不合法的 targetDir 会进行转换validate: (dir) => isValidPackageName(dir) || language.packageName.invalidMessage},{name: 'needsTypeScript',type: () => (isFeatureFlagsUsed ? null : 'toggle'),message: language.needsTypeScript.message,initial: false,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive},{name: 'needsJsx',type: () => (isFeatureFlagsUsed ? null : 'toggle'),message: language.needsJsx.message,initial: false,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive},{name: 'needsRouter',type: () => (isFeatureFlagsUsed ? null : 'toggle'),message: language.needsRouter.message,initial: false,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive},{name: 'needsPinia',type: () => (isFeatureFlagsUsed ? null : 'toggle'),message: language.needsPinia.message,initial: false,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive},{name: 'needsVitest',type: () => (isFeatureFlagsUsed ? null : 'toggle'),message: language.needsVitest.message,initial: false,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive},{name: 'needsE2eTesting',type: () => (isFeatureFlagsUsed ? null : 'select'),hint: language.needsE2eTesting.hint,message: language.needsE2eTesting.message,initial: 0,choices: (prev, answers) => [{title: language.needsE2eTesting.selectOptions.negative.title,value: false},{title: language.needsE2eTesting.selectOptions.cypress.title,description: answers.needsVitest? undefined: language.needsE2eTesting.selectOptions.cypress.desc,value: 'cypress'},{title: language.needsE2eTesting.selectOptions.nightwatch.title,description: answers.needsVitest? undefined: language.needsE2eTesting.selectOptions.nightwatch.desc,value: 'nightwatch'},{title: language.needsE2eTesting.selectOptions.playwright.title,value: 'playwright'}]},{name: 'needsEslint',type: () => (isFeatureFlagsUsed ? null : 'toggle'),message: language.needsEslint.message,initial: false,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive},{name: 'needsPrettier',type: (prev, values) => {if (isFeatureFlagsUsed || !values.needsEslint) {return null}return 'toggle'},message: language.needsPrettier.message,initial: false,active: language.defaultToggleOptions.active,inactive: language.defaultToggleOptions.inactive}],{onCancel: () => {throw new Error(red('✖') + ` ${language.errors.operationCancelled}`)}})} catch (cancelled) {console.log(cancelled.message)process.exit(1)}// `initial` won't take effect if the prompt type is null// so we still have to assign the default values hereconst {projectName,packageName = projectName ?? defaultProjectName,shouldOverwrite = argv.force,needsJsx = argv.jsx,needsTypeScript = argv.typescript,needsRouter = argv.router,needsPinia = argv.pinia,needsVitest = argv.vitest || argv.tests,needsEslint = argv.eslint || argv['eslint-with-prettier'],needsPrettier = argv['eslint-with-prettier']} = resultconst { needsE2eTesting } = resultconst needsCypress = argv.cypress || argv.tests || needsE2eTesting === 'cypress'const needsCypressCT = needsCypress && !needsVitestconst needsNightwatch = argv.nightwatch || needsE2eTesting === 'nightwatch'const needsNightwatchCT = needsNightwatch && !needsVitestconst needsPlaywright = argv.playwright || needsE2eTesting === 'playwright'

生成模版

创建项目输出文件夹

  const root = path.join(cwd, targetDir)// 递归删除文件夹和文件if (fs.existsSync(root) && shouldOverwrite) {emptyDir(root)} else if (!fs.existsSync(root)) {fs.mkdirSync(root)}function emptyDir(dir) {if (!fs.existsSync(dir)) {return}postOrderDirectoryTraverse(dir,(dir) => fs.rmdirSync(dir),(file) => fs.unlinkSync(file))
}export function postOrderDirectoryTraverse(dir, dirCallback, fileCallback) {for (const filename of fs.readdirSync(dir)) {if (filename === '.git') {continue}const fullpath = path.resolve(dir, filename)if (fs.lstatSync(fullpath).isDirectory()) {postOrderDirectoryTraverse(fullpath, dirCallback, fileCallback)dirCallback(fullpath)continue}fileCallback(fullpath)}
}

生成 packge.json

  console.log(`\n${language.infos.scaffolding} ${root}...`)const pkg = { name: packageName, version: '0.0.0' }fs.writeFileSync(path.resolve(root, 'package.json'), JSON.stringify(pkg, null, 2))

查找预设的模版文件

  const templateRoot = path.resolve(__dirname, 'template')// ejs 模版提供了渲染数据的回调const callbacks = []const render = function render(templateName) {const templateDir = path.resolve(templateRoot, templateName)renderTemplate(templateDir, root, callbacks)}
  • 预设模版文件
    在这里插入图片描述

根据路径生成模块文件

  • [node_modules, package.json, extensions.json, _gitignore, data.mjs] 以外的模块直接复制
function renderTemplate(src, dest, callbacks) {const stats = fs.statSync(src)// path.basename 返回当前路径的目录或文件if (stats.isDirectory()) {// skip node_moduleif (path.basename(src) === 'node_modules') {return}// if it's a directory, render its subdirectories and files recursively// dest 使用者要创建的目录地址fs.mkdirSync(dest, { recursive: true })// 递归文件夹创建文件for (const file of fs.readdirSync(src)) {renderTemplate(path.resolve(src, file), path.resolve(dest, file), callbacks)}return}const filename = path.basename(src)// 在上一步已经根据 dest 创建好了 package.jsonif (filename === 'package.json' && fs.existsSync(dest)) {// merge instead of overwritingconst existing = JSON.parse(fs.readFileSync(dest, 'utf8'))const newPackage = JSON.parse(fs.readFileSync(src, 'utf8'))// 合并、去重、排序(字符序) package.jsonconst pkg = sortDependencies(deepMerge(existing, newPackage))fs.writeFileSync(dest, JSON.stringify(pkg, null, 2) + '\n')return}if (filename === 'extensions.json' && fs.existsSync(dest)) {// merge instead of overwritingconst existing = JSON.parse(fs.readFileSync(dest, 'utf8'))const newExtensions = JSON.parse(fs.readFileSync(src, 'utf8'))const extensions = deepMerge(existing, newExtensions)fs.writeFileSync(dest, JSON.stringify(extensions, null, 2) + '\n')return}if (filename.startsWith('_')) {// rename `_file` to `.file`dest = path.resolve(path.dirname(dest), filename.replace(/^_/, '.'))}// 追加 .gitignoreif (filename === '_gitignore' && fs.existsSync(dest)) {// append to existing .gitignoreconst existing = fs.readFileSync(dest, 'utf8')const newGitignore = fs.readFileSync(src, 'utf8')fs.writeFileSync(dest, existing + '\n' + newGitignore)return}// data file for EJS templates// node 环境中使用 mjs 语法,import 只能导入 .mjs 模块if (filename.endsWith('.data.mjs')) {// use dest path as key for the data storedest = dest.replace(/\.data\.mjs$/, '')// Add a callback to the array for late usage when template files are being processedcallbacks.push(async (dataStore) => {const getData = (await import(pathToFileURL(src).toString())).default// Though current `getData` are all sync, we still retain the possibility of asyncdataStore[dest] = await getData({oldData: dataStore[dest] || {}})})return // skip copying the data file}// [node_modules, package.json, extensions.json, _gitignore, data.mjs] 以外的模块直接复制fs.copyFileSync(src, dest)
}

render 生成模版

  // Render base templaterender('base')// Add configs.if (needsJsx) {render('config/jsx')}if (needsRouter) {render('config/router')}if (needsPinia) {render('config/pinia')}if (needsVitest) {render('config/vitest')}if (needsCypress) {render('config/cypress')}if (needsCypressCT) {render('config/cypress-ct')}if (needsNightwatch) {render('config/nightwatch')}if (needsNightwatchCT) {render('config/nightwatch-ct')}if (needsPlaywright) {render('config/playwright')}if (needsTypeScript) {render('config/typescript')// Render tsconfigsrender('tsconfig/base')if (needsCypress) {render('tsconfig/cypress')}if (needsCypressCT) {render('tsconfig/cypress-ct')}if (needsPlaywright) {render('tsconfig/playwright')}if (needsVitest) {render('tsconfig/vitest')}if (needsNightwatch) {render('tsconfig/nightwatch')}if (needsNightwatchCT) {render('tsconfig/nightwatch-ct')}}// Render ESLint configif (needsEslint) {renderEslint(root, { needsTypeScript, needsCypress, needsCypressCT, needsPrettier })}// Render code template.// prettier-ignoreconst codeTemplate =(needsTypeScript ? 'typescript-' : '') +(needsRouter ? 'router' : 'default')render(`code/${codeTemplate}`)// Render entry file (main.js/ts).if (needsPinia && needsRouter) {render('entry/router-and-pinia')} else if (needsPinia) {render('entry/pinia')} else if (needsRouter) {render('entry/router')} else {render('entry/default')}

填充 ejs 模版数据

// An external data store for callbacks to share dataconst dataStore = {}// Process callbacksfor (const cb of callbacks) {await cb(dataStore)}// EJS template rendering// 从生成的 root 目录开始渲染 EJS 模版preOrderDirectoryTraverse(root,() => {},(filepath) => {if (filepath.endsWith('.ejs')) {const template = fs.readFileSync(filepath, 'utf-8')const dest = filepath.replace(/\.ejs$/, '')const content = ejs.render(template, dataStore[dest])fs.writeFileSync(dest, content)fs.unlinkSync(filepath)}})

根据生成项目是 ts 还是 js 后置处理

if (needsTypeScript) {// 转化 js 文件 -> ts 文件 (rename),删除掉原有的 jsconfig.json// 修改 index.html 中的 js 引入preOrderDirectoryTraverse(root,() => {},(filepath) => {if (filepath.endsWith('.js') && !FILES_TO_FILTER.includes(path.basename(filepath))) {const tsFilePath = filepath.replace(/\.js$/, '.ts')if (fs.existsSync(tsFilePath)) {fs.unlinkSync(filepath)} else {fs.renameSync(filepath, tsFilePath)}} else if (path.basename(filepath) === 'jsconfig.json') {fs.unlinkSync(filepath)}})// Rename entry in `index.html`const indexHtmlPath = path.resolve(root, 'index.html')const indexHtmlContent = fs.readFileSync(indexHtmlPath, 'utf8')fs.writeFileSync(indexHtmlPath, indexHtmlContent.replace('src/main.js', 'src/main.ts'))} else {// Remove all the remaining `.ts` files// 不需要 ts 时 删除掉目录中的 ts 文件preOrderDirectoryTraverse(root,() => {},(filepath) => {if (filepath.endsWith('.ts')) {fs.unlinkSync(filepath)}})}

根据需要的模块生成所有对应的 README.md 文件

  // 确定包管理器: pnpm > yarn > npmconst userAgent = process.env.npm_config_user_agent ?? ''const packageManager = /pnpm/.test(userAgent) ? 'pnpm' : /yarn/.test(userAgent) ? 'yarn' : 'npm'// README generation// 根据需要的文件生成所有的 READMEfs.writeFileSync(path.resolve(root, 'README.md'),generateReadme({projectName: result.projectName ?? result.packageName ?? defaultProjectName,packageManager,needsTypeScript,needsVitest,needsCypress,needsNightwatch,needsPlaywright,needsNightwatchCT,needsCypressCT,needsEslint}))

在这里插入图片描述

结尾提示

  // 生成项目完成,提示后续辅助工作// cd xxxif (root !== cwd) {// 假设生成的路径是:/Users/username/Projects/My Projectconst cdProjectName = path.relative(cwd, root)// 则控制台命令会被格式化为cd "My Project",而不是cd My Projectconsole.log(`  ${bold(green(`cd ${cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName}`))}`)}// pnpm|yarn|npm installconsole.log(`  ${bold(green(getCommand(packageManager, 'install')))}`)// prettier formatif (needsPrettier) {console.log(`  ${bold(green(getCommand(packageManager, 'format')))}`)}// npm devconsole.log(`  ${bold(green(getCommand(packageManager, 'dev')))}`)console.log()

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

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

相关文章

【算法】七大经典排序(插入,选择,冒泡,希尔,堆,快速,归并)(含可视化算法动图,清晰易懂,零基础入门)

​ 目录 一、排序的概念及其运用1.1 排序的概念1.2 排序的应用1.3 常见的排序算法 二、常见排序算法的实现2.1 插入排序2.1.1 直接插入排序2.1.2 希尔排序2.1.3 直接插入排序和希尔排序的性能对比 2.2 选择排序2.2.1 直接选择排序2.2.2 堆排序2.2.3 直接选择排序和堆排序的性能…

Mysql锁实战详细分析

1.mysql回表查询 在这里提起主要是用于说明mysql数据和索引的结构&#xff0c;有助于理解后续加锁过程中的一些问题。 mysql索引结构和表数据结构是相互独立的&#xff0c;根据索引查询&#xff0c;只能找到索引列和主键聚簇索引。如果select语句中不包含索引列&#xff0c;m…

陪诊系统|沈阳陪诊系统定制|陪诊软件保障患者安全与便利

陪诊系统是一种以专业医疗服务为核心的综合性陪同体系。它涵盖了医院前线咨询、专业陪诊、医后关怀等多个环节&#xff0c;提供全方位的医疗咨询服务和专业的医疗陪同服务。通过陪诊系统&#xff0c;患者可以获得更加便捷、高效、安全的医疗服务体验。陪诊系统的出现&#xff0…

多类场景、遍布各地,融云 IM 支撑多款应用全球增长

&#xff08;全网都在找的《社交泛娱乐出海作战地图》&#xff0c;点击获取&#x1f446;&#xff09; 无论是面向企业场景的工作流协同还是消费场景的网络效应形成&#xff0c;商务社交还是陌生人社交&#xff0c;IM 都是必备组件。IM 遍布互联网各角落&#xff0c;出现在所有…

【c++|SDL】开始使用之---demo

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 SDL 记录 1. hello word #include<SDL2/SDL.h>SDL_Window* g_pWindow 0; SDL_Renderer* g_pRenderer 0;int main(int argc, char* args[]) {//…

触控板窗口管理软件Swish mac中文版

Swish mac是一款触控板窗口管理工具&#xff0c;它允许用户通过简单的手势来控制窗口。Swish利用MacBook的触控板&#xff0c;使得用户可以更加便捷地管理窗口。它支持多种手势&#xff0c;例如捏合、拖动、放大和缩小等&#xff0c;使得用户可以轻松地实现窗口的切换、最小化、…

Milvus入门手册1.0

一、window环境搭建&#xff08;单机&#xff09; 1、docker安装 略 2、milvus安装 参考文档&#xff1a;https://milvus.io/docs/install_standalone-docker.md tips: &#xff08;1&#xff09;compose.yaml下载比较慢&#xff0c;可以在网络上找一份。 &#xff08;2&…

VScode集成python开发环境和基本插件下载配置

VSCode开发工具 下载VSCode VSCode官方首页&#xff1a;Visual Studio Code - Code Editing. Redefined 点击Download for Windows下载 安装过程一路下一步即可&#xff0c;其中建议勾选 将"通过Code打开"操作添加到Windows资源管理器目录上下文菜单方便我们直接通过…

虹科Pico汽车示波器 | 汽车免拆检修 | 2016款东风悦达起亚K5车发动机怠速抖动严重、加速无力

一、故障现象 一辆2016款东风悦达起亚K5车&#xff0c;搭载G4FJ发动机&#xff0c;累计行驶里程约为8.2万km。该车发动机怠速抖动严重、加速无力&#xff0c;同时发动机故障灯异常点亮&#xff0c;为此在其他维修厂更换了所有点火线圈和火花塞&#xff0c;故障依旧&#xff0c;…

309.最佳卖股票的时机包含冷冻期

一、题目分析 给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 卖出股票后&#xff0c;你无法在第二…

Nacos源码本地搭建流程及目录结构解读

下载地址 https://github.com/alibaba/nacos 目录结构 本地单机启动 首先maven编译完成之后在console下面找到Nacos 这个就是主启动类 然后再vm中配置参数-Dnacos.standalonetrue表示单机启动 当控制台没有报错 访问 http://localhost:8848/nacos 控制台界面登录进来之后显…

Linux—进程状态、僵尸进程、孤独进程、优先级

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、进程状态二、僵尸进程、孤儿进程1、Z(zombie)-僵尸进程2、僵尸进程危害3、孤儿进程 三、进…

String类讲解(1)

&#x1f435;本篇文章将讲解String类及其包含的方法 一、介绍String类 String属于引用类型&#xff0c;String类是Java的一个内置类&#xff0c;用于表示字符串&#xff0c;String类中具有许多方法&#xff0c;可以用来操作和处理字符串 二、字符串的构造 下面介绍三种构造字…

蓝桥杯每日一题2023.11.27

题目描述 星系炸弹 - 蓝桥云课 (lanqiao.cn) 题目分析 对于此题目一一枚举即可 #include<bits/stdc.h> using namespace std; bool is_r(int n) {if((n % 4 0 && n % 100 ! 0)|| n % 400 0)return true;return false; } int mm[13] {0, 31, 28, 31, 30, 3…

万字详解,和你用RAG+LangChain实现chatpdf

像chatgpt这样的大语言模型(LLM)可以回答很多类型的问题,但是,如果只依赖LLM,它只知道训练过的内容,不知道你的私有数据:如公司内部没有联网的企业文档,或者在LLM训练完成后新产生的数据。(即使是最新的GPT-4 Turbo,训练的数据集也只更新到2023年4月)所以,如果我们…

Docker入门教程

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

微服务--02--Nacos注册中心

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 服务注册和发现手动发送Http请求的方式存在问题注册中心原理 Nacos注册中心配置服务注册服务发现小结&#xff1a; 服务注册和发现 手动发送Http请求的方式存在问题…

Compensated Summation/Kahan‘s Summation的理解

阅读《Efficient Generation of Error-Inducing Floating-Point Inputs via Symbolic Execution》这篇论文时&#xff0c;文中提到的Commpensated Summation没看太懂&#xff0c;代码如下&#xff1a; 查阅资料发现Compensated Summation也叫Kahan’s Summation&#xff0c;该…

Termius 一款优秀的跨平台 SSH 客户端工具

&#x1f525;&#x1f525;&#x1f525; 作为程序员或者运维管理人员&#xff0c;我们经常需要使用终端工具来进行服务器管理及各种操作&#xff0c;比如部署项目、调试代码、查看/优化服务、管理服务器等。 而实现远程服务器连接需要借助 SSH 协议来进行&#xff0c;SSH&am…

青少年CTF之PHP特性练习(1-5)

青少年CTF-PHP特性练习 文章目录 青少年CTF-PHP特性练习PHP特性01PHP特性02PHP特性03PHP特性04PHP特性05 PHP特性01 看给出的源码&#xff0c;两个变量的值加密后的MD5相同 <?php$s1 "%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47…