umi的脚本太多了,也都很有意思,因此有必要单独拎出来了解一下。 先来说几个包
chalk 日志加颜色
给命令行的日志加上颜色显示出来
import chalk from 'chalk';
const log = console.log;
// Combine styled and normal strings
log(chalk.blue('Hello') + ' World' + chalk.red('!'));
git-repo-info 仓库信息
获取根目录中 .git 文件的描述信息比如分支等
var getRepoInfo = require('git-repo-info');
var info = getRepoInfo();
// info.branch // current branch
// info.sha // current sha
// info.abbreviatedSha // first 10 chars of the current sha
// info.tag // tag for the current sha (or `null` if no tag exists)
// info.lastTag // tag for the closest tagged ancestor
// // (or `null` if no ancestor is tagged)
// info.commitsSinceLastTag // number of commits since the closest tagged ancestor
// // (`0` if this commit is tagged, or `Infinity` if no ancestor is tagged)
// info.committer // committer for the current sha
// info.committerDate // commit date for the current sha
// info.author // author for the current sha
// info.authorDate // authored date for the current sha
// info.commitMessage // commit message for the current sha
// info.root // root directory for the Git repo or submodule
// // (if in a worktree, this is the directory containing the original copy)
// info.commonGitDir // directory containing Git metadata for this repo or submodule
// // (if in a worktree, this is the primary Git directory for the repo)
// info.worktreeGitDir // if in a worktree, the directory containing Git metadata specific to
// this worktree; otherwise, this is the same as `commonGitDir`.
zx 高效写shell脚本
Google的zx库 可以帮助我们更加高效地用Nodejs写shell 脚本。
import 'zx/globals' // 会自动加载 $ 命令
let flags = [
'--oneline',
'--decorate',
'--color',
]
await $`git log ${flags}`
cross-spawn 跨平台命令行
编写跨平台的命令
// 原生 node调用时,需要区分 Windows、OSX 和 Linux 环境,要不然会报错
const process = require('process');
const { spawn } = require('child_process');
spawn('npm', {
stdio: 'inherit',
// 仅在当前运行环境为 Windows 时,才使用 shell
shell: process.platform === 'win32'
});
cross-spawn 可以根据平台自动补全对应配置,解决了跨平台不兼容的问题
const spawn = require('cross-spawn');
// Spawn NPM asynchronously
const child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
umi-scripts bootstrap
monorepo时,在packages/ 文件夹下只需要新建一个文件名,再执行这个命令,就可以新建一个代码仓库,这个代码仓库包括 package.json, README.md, tsconfig.json 等描述信息。下面分步骤对代码进行说明
执行命令 umi-scripts bootstrap someNewRepo。
源码中只用了 force 参数,用于更新所以代码仓库,比如 umi-scripts bootstrap --force
这里有个小疑问,为啥不获取参数 argv: { _: [ 'someNewRepo' ] },当和 packages中的文件名称不匹配时,生成一个新的代码仓库。
import 'zx/globals';
import { PATHS, SCRIPTS } from './.internal/constants';
import { setExcludeFolder } from './.internal/utils';
(async () => {
const root = PATHS.ROOT;
// 获取根目录下的 packages 文件夹
const pkgDir = path.join(root, 'packages');
// 获取所有的文件夹名称
// '["ast","babel-preset-umi","bundler-esbuild",
// "bundler-utils","bundler-vite","bundler-webpack",
// "core","create-umi","demo","lint","max","mfsu",
// "plugin-docs","plugin-run","plugins","preset-umi",
// "preset-vue","renderer-react","renderer-vue",
// "server","testing","umi","utils"]'
const pkgs = await fs.readdir(pkgDir);
// 遍历 packages 下的所有文件夹名称
for (const pkg of pkgs) {
// console.log(pkg, 'pppp')
if (pkg.charAt(0) === '.') continue;
if (!(await fs.stat(path.join(pkgDir, pkg))).isDirectory()) continue;
console.log(argv, 'argv====') // { _: [ 'someNewRepo' ] }
await bootstrapPkg({
pkgDir,
pkg,
force: argv.force,
});
}
function getName(pkgName: string) {
if (['umi'].includes(pkgName)) {
return pkgName;
} else {
return `@umijs/${pkgName}`;
}
}
function getVersion() {
return require(PATHS.LERNA_CONFIG).version;
}
async function bootstrapPkg(opts: any) {
const pkgDir = path.join(opts.pkgDir, opts.pkg);
if (!opts.force && fs.existsSync(path.join(pkgDir, 'package.json'))) {
console.log(`${opts.pkg} exists`);
} else {
// 当某个文件夹不下存在 package.json,生成一个子代码仓库
// 包括: package.json、 README.md、tsconfig.json、.fatherrc.ts、
const name = getName(opts.pkg);
// package.json
const pkgPkgJSONPath = path.join(pkgDir, 'package.json');
const hasPkgJSON = fs.existsSync(pkgPkgJSONPath);
const pkgPkgJSON = hasPkgJSON ? require(pkgPkgJSONPath) : {};
fs.writeJSONSync(
pkgPkgJSONPath,
Object.assign(
{
name,
version: getVersion(),
description: name,
main: 'dist/index.js',
types: 'dist/index.d.ts',
files: ['dist'],
scripts: {
build: SCRIPTS.BUILD,
'build:deps': SCRIPTS.BUNDLE_DEPS,
dev: SCRIPTS.DEV,
},
repository: {
type: 'git',
url: 'https://github.com/umijs/umi',
},
authors: [
'chencheng <sorrycc@gmail.com> (https://github.com/sorrycc)',
],
license: 'MIT',
bugs: 'https://github.com/umijs/umi/issues',
homepage: `https://github.com/umijs/umi/tree/master/packages/${opts.pkg}#readme`,
publishConfig: {
access: 'public',
},
},
{
...(hasPkgJSON
? {
authors: pkgPkgJSON.authors,
bin: pkgPkgJSON.bin,
files: pkgPkgJSON.files,
scripts: pkgPkgJSON.scripts,
description: pkgPkgJSON.description,
dependencies: pkgPkgJSON.dependencies,
devDependencies: pkgPkgJSON.devDependencies,
compiledConfig: pkgPkgJSON.compiledConfig,
}
: {}),
},
),
{ spaces: ' ' },
);
// README.md
await fs.writeFile(
path.join(pkgDir, 'README.md'),
`# ${name}\n\nSee our website [umijs](https://umijs.org) for more information.`,
'utf-8',
);
// tsconfig.json
await fs.writeFile(
path.join(pkgDir, 'tsconfig.json'),
`{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"]
}\n`,
'utf-8',
);
// .fatherrc.ts
await fs.writeFile(
path.join(pkgDir, '.fatherrc.ts'),
`import { defineConfig } from 'father';
export default defineConfig({
extends: '../../.fatherrc.base.ts',
});\n`,
'utf-8',
);
// src/index.ts
const srcDir = path.join(pkgDir, 'src');
if (!fs.existsSync(srcDir)) {
await $`mkdir ${srcDir}`;
}
if (!fs.existsSync(path.join(pkgDir, 'src', 'index.ts'))) {
await fs.writeFile(
path.join(pkgDir, 'src', 'index.ts'),
`
export default () => {
return '${name}';
};\n`.trimLeft(),
'utf-8',
);
await fs.writeFile(
path.join(pkgDir, 'src', 'index.test.ts'),
`
import index from './index';
test('normal', () => {
expect(index()).toEqual('${name}');
});\n`.trimLeft(),
'utf-8',
);
}
// set excludeFolder for webstorm
setExcludeFolder({ pkg: opts.pkg, cwd: root });
console.log(chalk.green(`${opts.pkg} bootstrapped`));
}
}
})();