Vue 发布新版脚手架工具,300 行代码轻盈新生!

应用开发2025-11-03 10:21:18321

 1. 前言

美国时间 2021 年 10 月 7 日早晨,布新版脚Vue 团队等主要贡献者举办了一个 Vue Contributor Days 在线会议,手架生蒋豪群[1](知乎胖茶[2],工具Vue.js 官方团队成员,行代Vue-CLI 核心开发),码轻在会上公开了create-vue[3],盈新一个全新的布新版脚脚手架工具。

create-vue使用npm init vue@next一行命令,手架生就能快如闪电般初始化好基于vite的工具Vue3项目。

本文就是行代通过调试和大家一起学习这个300余行的源码。

阅读本文,码轻你将学到:

1. 学会全新的盈新官方脚手架工具 create-vue 的使用和原理

2. 学会使用 VSCode 直接打开 github 项目

3. 学会使用测试用例调试源码

4. 学以致用,为公司初始化项目写脚手架工具。布新版脚

5. 等等

2. 使用 npm init vue@next 初始化 vue3 项目

create-vue github README[4]上写着,手架生An easy way to start a Vue project。工具一种简单的初始化vue项目的方式。

npm init vue@next 

估计大多数读者,第一反应是这样竟然也可以,这么简单快捷?

忍不住想动手在控制台输出命令,我在终端试过,见下图。

npm init vue@next

最终cd vue3-project、npm install 、npm run dev打开页面http://localhost:3000[5]。

初始化页面

2.1 npm init && npx

为啥 npm init 也可以直接初始化一个项目,服务器托管带着疑问,我们翻看 npm 文档。

npm init[6]

npm init 用法: 

npm init [--force|-f|--yes|-y|--scope]  npm init <@scope> (same as `npx <@scope>/create`)  npm init [<@scope>/]<name> (same as `npx [<@scope>/]create-<name>`) 

npm init <initializer> 时转换成npx命令:

 npm init foo -> npx create-foo  npm init @usr/foo -> npx @usr/create-foo  npm init @usr -> npx @usr/create

看完文档,我们也就理解了: 

# 运行  npm init vue@next  # 相当于  npx create-vue@next 

我们可以在这里create-vue[7],找到一些信息。或者在npm create-vue[8]找到版本等信息。

其中@next是指定版本,通过npm dist-tag ls create-vue命令可以看出,next版本目前对应的是3.0.0-beta.6。 

npm dist-tag ls create-vue  - latest: 3.0.0-beta.6  - next: 3.0.0-beta.6 

发布时 npm publish --tag next 这种写法指定 tag。默认标签是latest。

可能有读者对 npx 不熟悉,这时找到阮一峰老师博客 npx 介绍[9]、nodejs.cn npx[10]

npx 是一个非常强大的命令,从 npm 的 5.2 版本(发布于 2017 年 7 月)开始可用。

简单说下容易忽略且常用的场景,npx有点类似小程序提出的随用随走。

轻松地运行本地命令 

node_modules/.bin/vite -v  # vite/2.6.5 linux-x64 node-v14.16.0  # 等同于  # package.json script: "vite -v"  # npm run vite  npx vite -v  # vite/2.6.5 linux-x64 node-v14.16.0 

使用不同的 Node.js 版本运行代码某些场景下可以临时切换 node 版本,有时比 nvm 包管理方便些。 

npx node@14 -v  # v14.18.0  npx -p node@14 node -v   # v14.18.0 

无需安装的命令执行 。

# 启动本地静态服务  npx http-server   # 无需全局安装  npx @vue/cli create vue-project  # @vue/cli 相比 npm init vue@next npx create-vue@next 很慢。  # 全局安装  npm i -g @vue/cli  vue create vue-project 

npx vue-cli

npm init vue@next (npx create-vue@next) 快的服务器租用原因,主要在于依赖少(能不依赖包就不依赖),源码行数少,目前index.js只有300余行。

3. 配置环境调试源码

3.1 克隆 create-vue 项目

本文仓库地址 create-vue-analysis[11],求个star~ 

# 可以直接克隆我的仓库,我的仓库保留的 create-vue 仓库的 git 记录  git clone https://github.com/lxchuan12/create-vue-analysis.git  cd create-vue-analysis/create-vue  npm i 

当然不克隆也可以直接用 VSCode 打开我的仓库。https://open.vscode.dev/lxchuan12/create-vue-analysis

顺带说下:我是怎么保留 create-vue 仓库的 git 记录的。 

# 在 github 上新建一个仓库 `create-vue-analysis` 克隆下来  git clone https://github.com/lxchuan12/create-vue-analysis.git  cd create-vue-analysis  git subtree add --prefix=create-vue https://github.com/vuejs/create-vue.git main  # 这样就把 create-vue 文件夹克隆到自己的 git 仓库了。且保留的 git 记录 

关于更多 git subtree,可以看Git Subtree 简明使用手册[12]

3.2 package.json 分析 

// create-vue/package.json  {    "name": "create-vue",    "version": "3.0.0-beta.6",    "description": "An easy way to start a Vue project",    "type": "module",    "bin": {      "create-vue": "outfile.cjs"    },  } 

bin指定可执行脚本。也就是我们可以使用 npx create-vue 的原因。

outfile.cjs 是打包输出的JS文件 

{    "scripts": {      "build": "esbuild --bundle index.js --format=cjs --platform=node --outfile=outfile.cjs",      "snapshot": "node snapshot.js",      "pretest": "run-s build snapshot",      "test": "node test.js"    },  } 

执行 npm run test 时,会先执行钩子函数 pretest。run-s 是 npm-run-all[13] 提供的命令。run-s build snapshot 命令相当于 npm run build && npm run snapshot。

根据脚本提示,亿华云我们来看 snapshot.js 文件。

3.3 生成快照 snapshot.js

这个文件主要作用是根据const featureFlags = [typescript, jsx, router, vuex, with-tests] 组合生成31种加上 default 共计 32种 组合,生成快照在 playground目录。

因为打包生成的 outfile.cjs 代码有做一些处理,不方便调试,我们可以修改为index.js便于调试。 

// 路径 create-vue/snapshot.js  const bin = path.resolve(__dirname, ./outfile.cjs)  // 改成 index.js 便于调试  const bin = path.resolve(__dirname, ./index.js) 

我们可以在for和 createProjectWithFeatureFlags 打上断点。

createProjectWithFeatureFlags其实类似在终端输入如下执行这样的命令

node ./index.js --xxx --xxx --force   function createProjectWithFeatureFlags(flags) {    const projectName = flags.join(-)    console.log(`Creating project ${projectName}`)    const { status } = spawnSync(      node,      [bin, projectName, ...flags.map((flag) => `--${flag}`), --force],      {        cwd: playgroundDir,        stdio: [pipe, pipe, inherit]      }    )    if (status !== 0) {      process.exit(status)    }  }  // 路径 create-vue/snapshot.js  for (const flags of flagCombinations) {    createProjectWithFeatureFlags(flags)  } 

调试:VSCode打开项目,VSCode高版本(1.50+)可以在 create-vue/package.json => scripts => "test": "node test.js"。鼠标悬停在test上会有调试脚本提示,选择调试脚本。如果对调试不熟悉,可以看我之前的文章koa-compose,写的很详细。

调试时,大概率你会遇到:create-vue/index.js 文件中,__dirname 报错问题。可以按照如下方法解决。在 import 的语句后,添加如下语句,就能愉快的调试了。 

// 路径 create-vue/index.js  // 解决办法和nodejs issues  // https://stackoverflow.com/questions/64383909/dirname-is-not-defined-in-node-14-version  // https://github.com/nodejs/help/issues/2907  import { fileURLToPath } from url;  import { dirname } from path;  const __filename = fileURLToPath(import.meta.url);  const __dirname = dirname(__filename); 

接着我们调试 index.js 文件,来学习。

4. 调试 index.js 主流程

回顾下上文 npm init vue@next 初始化项目的。

npm init vue@next

单从初始化项目输出图来看。主要是三个步骤。 

1. 输入项目名称,默认值是 vue-project  2. 询问一些配置 渲染模板等  3. 完成创建项目,输出运行提示   async function init() {    // 省略放在后文详细讲述  }  // async 函数返回的是Promise 可以用 catch 报错  init().catch((e) => {    console.error(e)  }) 

4.1 解析命令行参数 

// 返回运行当前脚本的工作目录的路径。  const cwd = process.cwd()  // possible options: // --default  // --typescript / --ts  // --jsx  // --router / --vue-router  // --vuex // --with-tests / --tests / --cypress  // --force (for force overwriting)  const argv = minimist(process.argv.slice(2), {      alias: {          typescript: [ts],          with-tests: [tests, cypress],          router: [vue-router]      },      // all arguments are treated as booleans      boolean: true  }) 

minimist[14]

简单说,这个库,就是解析命令行参数的。看例子,我们比较容易看懂传参和解析结果。 

$ node example/parse.js -a beep -b boop  { _: [], a: beep, b: boop }  $ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz  { _: [ foo, bar, baz ],    x: 3,    y: 4,    n: 5,    a: true,    b: true,    c: true,    beep: boop } 

比如 

npm init vue@next --vuex --force 

4.2 如果设置了 feature flags 跳过 prompts 询问

这种写法方便代码测试等。直接跳过交互式询问,同时也可以省时间。 

// if any of the feature flags is set, we would skip the feature prompts    // use `??` instead of `||` once we drop Node.js 12 support    const isFeatureFlagsUsed =      typeof (argv.default || argv.ts || argv.jsx || argv.router || argv.vuex || argv.tests) ===      boolean  // 生成目录    let targetDir = argv._[0]    // 默认 vue-projects    const defaultProjectName = !targetDir ? vue-project : targetDir    // 强制重写文件夹,当同名文件夹存在时    const forceOverwrite = argv.force 

4.3 交互式询问一些配置

如上文npm init vue@next 初始化的图示

 输入项目名称  还有是否删除已经存在的同名目录  询问使用需要 JSX Router vuex cypress 等。  let result = {}    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 Vuex for state management? (TODO)      // - Add Cypress for testing?      result = await prompts(        [          {            name: projectName,            type: targetDir ? null : text,            message: Project name:,            initial: defaultProjectName,           onState: (state) => (targetDir = String(state.value).trim() || defaultProjectName)          },          // 省略若干配置          {            name: needsTests,            type: () => (isFeatureFlagsUsed ? null : toggle),            message: Add Cypress for testing?,            initial: false,            active: Yes,            inactive: No          }        ],        {          onCancel: () => {            throw new Error(red(✖) +  Operation cancelled)          }        }      ]      )    } catch (cancelled) {      console.log(cancelled.message)      // 退出当前进程。      process.exit(1)    } 

4.4 初始化询问用户给到的参数,同时也会给到默认值 

// `initial` wont take effect if the prompt type is null    // so we still have to assign the default values here    const {      packageName = toValidPackageName(defaultProjectName),      shouldOverwrite,      needsJsx = argv.jsx,      needsTypeScript = argv.typescript,      needsRouter = argv.router,      needsVuex = argv.vuex,      needsTests = argv.tests    } = result    const root = path.join(cwd, targetDir)    // 如果需要强制重写,清空文件夹    if (shouldOverwrite) {      emptyDir(root)      // 如果不存在文件夹,则创建    } else if (!fs.existsSync(root)) {      fs.mkdirSync(root)    }    // 脚手架项目目录    console.log(`\nScaffolding project in ${root}...`)   // 生成 package.json 文件    const pkg = { name: packageName, version: 0.0.0 }    fs.writeFileSync(path.resolve(root, package.json), JSON.stringify(pkg, null, 2)) 

4.5 根据模板文件生成初始化项目所需文件 

// todo:   // work around the esbuild issue that `import.meta.url` cannot be correctly transpiled   // when bundling for node and the format is cjs   // const templateRoot = new URL(./template, import.meta.url).pathname   const templateRoot = path.resolve(__dirname, template)   const render = function render(templateName) {     const templateDir = path.resolve(templateRoot, templateName)     renderTemplate(templateDir, root)   }   // Render base template   render(base)    // 添加配置   // Add configs.   if (needsJsx) {     render(config/jsx)  }   if (needsRouter) {     render(config/router)   }   if (needsVuex) {     render(config/vuex)   }   if (needsTests) {     render(config/cypress)   }   if (needsTypeScript) {     render(config/typescript)   } 

4.6 渲染生成代码模板 

// Render code template.    // prettier-ignore    const codeTemplate =      (needsTypeScript ? typescript- : ) +      (needsRouter ? router : default)    render(`code/${codeTemplate}`)    // Render entry file (main.js/ts).    if (needsVuex && needsRouter) {      render(entry/vuex-and-router)    } else if (needsVuex) {      render(entry/vuex)    } else if (needsRouter) {      render(entry/router)    } else {      render(entry/default)    } 

4.7 如果配置了需要 ts

重命名所有的 .js 文件改成 .ts。重命名 jsconfig.json 文件为 tsconfig.json 文件。

jsconfig.json[15] 是VSCode的配置文件,可用于配置跳转等。

把index.html 文件里的 main.js 重命名为 main.ts。 

// Cleanup.  if (needsTypeScript) {     // rename all `.js` files to `.ts`      // rename jsconfig.json to tsconfig.json      preOrderDirectoryTraverse(        root,        () => {},        (filepath) => {          if (filepath.endsWith(.js)) {            fs.renameSync(filepath, filepath.replace(/.js$/, .ts))          } else if (path.basename(filepath) === jsconfig.json) {            fs.renameSync(filepath, filepath.replace(/jsconfig.json$/, tsconfig.json))          }        }      )      // 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))    } 

4.8 配置了不需要测试

因为所有的模板都有测试文件,所以不需要测试时,执行删除 cypress、/__tests__/ 文件夹 

if (!needsTests) {     // All templates assumes the need of tests.     // If the user doesnt need it:     // rm -rf cypress **/__tests__/     preOrderDirectoryTraverse(       root,       (dirpath) => {         const dirname = path.basename(dirpath)         if (dirname === cypress || dirname === __tests__) {           emptyDir(dirpath)           fs.rmdirSync(dirpath)         }       },       () => {}     )   } 

4.9 根据使用的 npm / yarn / pnpm 生成README.md 文件,给出运行项目的提示 

// Instructions:    // Supported package managers: pnpm > yarn > npm    // Note: until <https://github.com/pnpm/pnpm/issues/3505> is resolved,    // it is not possible to tell if the command is called by `pnpm init`.    const packageManager = /pnpm/.test(process.env.npm_execpath)      ? pnpm      : /yarn/.test(process.env.npm_execpath)      ? yarn      : npm    // README generation    fs.writeFileSync(      path.resolve(root, README.md),      generateReadme({        projectName: result.projectName || defaultProjectName,        packageManager,        needsTypeScript,        needsTests      })    )    console.log(`\nDone. Now run:\n`)    if (root !== cwd) {      console.log(`  ${bold(green(`cd ${path.relative(cwd, root)}`))}`)    }    console.log(`  ${bold(green(getCommand(packageManager, install)))}`)    console.log(`  ${bold(green(getCommand(packageManager, dev)))}`)    console.log() 

5. npm run test => node test.js 测试 

// create-vue/test.js  import fs from fs  import path from path  import { fileURLToPath } from url  import { spawnSync } from child_process  const __dirname = path.dirname(fileURLToPath(import.meta.url))  const playgroundDir = path.resolve(__dirname, ./playground/)  for (const projectName of fs.readdirSync(playgroundDir)) {    if (projectName.endsWith(with-tests)) {      console.log(`Running unit tests in ${projectName}`)      const unitTestResult = spawnSync(pnpm, [test:unit:ci], {        cwd: path.resolve(playgroundDir, projectName),        stdio: inherit,        shell: true      })      if (unitTestResult.status !== 0) {        throw new Error(`Unit tests failed in ${projectName}`)      }      console.log(`Running e2e tests in ${projectName}`)      const e2eTestResult = spawnSync(pnpm, [test:e2e:ci], {        cwd: path.resolve(playgroundDir, projectName),        stdio: inherit,        shell: true      })     if (e2eTestResult.status !== 0) {        throw new Error(`E2E tests failed in ${projectName}`)      }    }  } 

主要对生成快照时生成的在 playground 32个文件夹,进行如下测试。 

pnpm test:unit:ci  pnpm test:e2e:ci  

6. 总结

我们使用了快如闪电般的npm init vue@next,学习npx命令了。学会了其原理。 

npm init vue@next => npx create-vue@next 

快如闪电的原因在于依赖的很少。很多都是自己来实现。如:Vue-CLI中 vue create vue-project 命令是用官方的npm包validate-npm-package-name[16],删除文件夹一般都是使用 rimraf[17]。而 create-vue 是自己实现emptyDir和isValidPackageName。

非常建议读者朋友按照文中方法使用VSCode调试 create-vue 源码。源码中还有很多细节文中由于篇幅有限,未全面展开讲述。 

本文地址:http://www.bzve.cn/html/355c63899006.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

热门文章

全站热门

电脑安装无损分区教程(一步步教你如何在电脑上进行无损分区,保护你的数据安全)

10月19日消息,Canonical今天正式开始面向全球范围内的测试人员放出Ubuntu 15.10 RC(Wily Werewolf),也就是最终候选版镜像下载。其目的就是为了找出最后可能存在的bug,从而为本月22日即将发布的正式版做好准备。• Ubuntu 15.10 RC最终候选版及衍生版安装镜像下载:点击此处>>Ubuntu 15.10在开发上已经处于最终冻结状态,不出现严重bug的话,将不会再对其进行任何更新和调整。此外,Ubuntu 15.10的各种衍生版本,例如Ubuntu、Kubuntu、Lubuntu、Ubuntu Core、Ubuntu GNOME、Ubuntu Kylin、Ubuntu MATE、Ubuntu Server、Ubuntu Studio以及Xubuntu也都开始提供测试版下载。从Canonical官方的ISO镜像追踪页面上来看,Lubuntu以及Xubuntu两个版本所存在的bug最多,其中的部分问题甚至会影响到用户的正常安装,因此暂时不推荐大家尝鲜这些版本。假如你感兴趣的话,现在就可以到Ubuntu的ISO Tracker上下载这些版本的镜像,正式版预计将于10月22日正式发布。相关推荐:在Ubuntu系统下直接运行ISO文件的方法详解Ubuntu 15.10系统10月22日发布 采用Linux Kernel 4.2内核

电脑打印结婚请柬教程(轻松DIY,高效方便,一键打印定制结婚请柬)

电脑U盘接口安装教程(轻松学会安装U盘接口的方法,方便文件传输和存储)

掌握平板电脑4指操作技巧,高效利用设备(简单易学的平板电脑4指操作教程,助您成为高手)

在Ubuntu中怎么安装JDK图文解析,对于很多不知道怎么操作的朋友可以参考本文,希望能给大家带来帮助!方法/步骤1,到Oracle官网下载相关的JDK2,假设jdk安装文件在桌面,我们指定的安装目录是:/usr/local/java 。可是系统安装后在/usr/local下并没有java目录,这需要我们去创建一个java文件夹3,打开终端(terminal)切换到桌面下,执行复制sudo cp jdk-6u30-linux-i586.bin /usr/local/java/安装jdk:切换到root用户下,(注:假如因忘记密码而认证失败,可以先修改root用户的密码,再执行,修改root用户密码如图)更改jdk-6u30-linux-i586.bin权限运行jdk-6u30-linux-i586.bin当看到下图情况时,说明你安装成功了。这时在/usr/local/java目录下就多了一个jdk1.6.0_30文件夹,可以查看一下注:假如因忘记密码而认证失败,可以先修改root用户的密码,再执行,修改root用户密码以上就是在Ubuntu中怎么安装JDK图文解析教程,大家看明白了吗?主要大家按照上面的步骤进行,即可成功安装JDK,希望能对大家有所帮助!

Justniffer 是一个可用于替代 Snort 的网络协议分析器。它非常流行,可交互式地跟踪/探测一个网络连接。它能从实时环境中抓取流量,支持 “lipcap” 和 “tcpdump” 文件格式。它可以帮助用户分析一个用 wireshark 难以抓包的复杂网络。尤其是它可以有效的帮助你分析应用层流量,能提取类似图像、脚本、HTML 等 http 内容。Justniffer 有助于理解不同组件之间是如何通信的。功能Justniffer 可以收集一个复杂网络的所有流量而不影响系统性能,这是Justniffer 的一个优势,它还可以保存日志用于之后的分析,Justniffer 其它一些重要功能包括:1.可靠的 TCP 流重建它可以使用主机 Linux 内核的一部分用于记录并重现 TCP 片段和 IP 片段。2.日志保存日志用于之后的分析,并能自定义保存内容和时间。3.可扩展可以通过外部的 python、 perl 和 bash 脚本扩展来从分析报告中获取一些额外的结果。4.性能管理基于连接时间、关闭时间、响应时间或请求时间等提取信息。安装Justniffer 可以通过 PPA 安装:运行下面命令添加库:$ sudo add-apt-repository ppa:oreste-notelli/ppa更新系统:$ sudo apt-get update安装 Justniffer 工具:$ sudo apt-get install justniffermake 的时候失败了,然后我运行下面的命令并尝试重新安装服务$ sudo apt-get -f install示例首先用 -v 选项验证安装的 Justniffer 版本,你需要用超级用户权限来使用这个工具。$ sudo justniffer -V示例输出:1.以类似 apache 的格式导出 eth1 接口流量,显示到终端。$ sudo  justniffer -i eth1示例输出:2.可以用下面的选项跟踪正在运行的tcp 流$ sudo  justniffer -i eth1 -r示例输出:3.获取 web 服务器的响应时长$ sudo justniffer -i eth1 -a %response.time示例输出:4.使用 Justniffer 读取一个 tcpdump 抓取的文件首先,用 tcpdump 抓取流量。$ sudo tcpdump -w /tmp/file.cap -s0 -i eth0然后用 Justniffer 访问数据$ justniffer -f file.cap示例输出:5.只抓取http 数据$ sudo justniffer -i eth1 -r -p port 80 or port 8080示例输出:6.获取一个指定主机的 http 数据$ justniffer -i eth1 -r -p host 192.168.1.250 and tcp port 80示例输出:7.以更精确的格式抓取数据当你输入 justniffer -h 的时候你可以看到很多用于以更精确的方式获取数据的格式关键字。$ justniffer -h示例输出:让我们用 Justniffer 根据预先定义的参数提取数据。$ justniffer -i eth1 -l %request.timestamp %request.header.host %request.url %response.time示例输出:其中还有很多你可以探索的选项。总结Justniffer 是一个很好的用于网络测试的工具。在我看来对于那些用 Snort 来进行网络探测的用户来说,Justniffer 是一个更简单的工具。它提供了很多 格式关键字 用于按照你的需要精确地提取数据。你可以用.cap 文件格式记录网络信息,之后用于分析监视网络服务性能。

作为一个经常喜欢敲命令的人,可能要同时做很多操作,Linux各个桌面的窗口切换有多那啥,这里就不吐槽了, 我总是在想要做另外一个操作,但又不想结束当前的工作,之前我习惯于再打开一个终端,但是后来终端越来越多导致我想找回原来的工作的时候就变的很费力,而且对桌面有洁癖的人不允许任务栏太杂 后来发现了一款终端软件terminator,它支持分割终端,并可以在终端中快速切换.还有一款下拉式的终端软件Guake可以随意呼出隐藏.下面就一一介绍一下.1 安装Terminator复制代码代码如下:2 使用复制代码代码如下:复制代码代码如下:3 Guake复制代码代码如下:在文本模式的环境中使用一个窗口管理器 – 这听起来有点不可思议, 是吧? 然而,你应该记得当 Web 浏览器第一次实现分页浏览的时候吧? 在当时, 这是在可用性上的一个重大进步,它减少了桌面任务栏的杂乱无章和繁多的窗口列表。 对于你的浏览器来说,你只需要一个按钮便可以在浏览器中切换到你打开的每个单独网站, 而不是针对每个网站都有一个任务栏或导航图标。 这个功能非常有意义。若有时你同时运行着几个虚拟终端,你便会遇到相似的情况; 在这些终端之间跳转,或每次在任务栏或窗口列表中找到你所需要的那一个终端,都可能会让你觉得麻烦。 拥有一个文本模式的窗口管理器不仅可以让你像在同一个终端窗口中运行多个 shell 会话,而且你甚至还可以将这些窗口排列在一起。另外,这样还有另一个好处:可以将这些窗口进行分离和重新连接。想要看看这是如何运行的最好方式是自己尝试一下。在一个终端窗口中,输入 screen (在大多数发行版本中,它已经默认安装了或者可以在软件包仓库中找到)。 某些欢迎的文字将会出现 – 只需敲击 Enter 键这些文字就会消失。 现在运行一个交互式的文本模式的程序,例如 nano, 并关闭这个终端窗口。在一个正常的 shell 对话中, 关闭窗口将会终止所有在该终端中运行的进程 – 所以刚才的 Nano 编辑对话也就被终止了, 但对于 screen 来说,并不是这样的。打开一个新的终端并输入如下命令:复制代码代码如下:复制代码代码如下:复制代码代码如下:上图中, tmux 开启了两个窗格: 左边是 Vim 正在编辑一个配置文件,而右边则展示着指导手册页。

热门文章

友情链接

滇ICP备2023006006号-39