Skip to content

Commit

Permalink
feat: tnf generate (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
sorrycc authored Nov 7, 2024
1 parent 4d142b3 commit c1dbe5a
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/rich-lobsters-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@umijs/tnf': patch
---

feat: tnf generate page
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ $ npx serve dist -s

## Commands

> WIP. More commands will be added in the future.
- `tnf create <project-name> --template=<template-name>`: Create a new project with the given template.
- `tnf build`: Build the project.
- `tnf dev`: Start the development server.
- `tnf generate <type> <name>`: Generate a new page (or component and other types in the future).
- `tnf preview`: Preview the product after building the project.

## API
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/express-http-proxy": "^1.6.6",
"@types/fs-extra": "^11.0.4",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/spdy": "^3.4.9",
Expand All @@ -46,10 +47,12 @@
"cors": "^2.8.5",
"express": "^4.21.1",
"express-http-proxy": "^2.1.1",
"fs-extra": "^11.1.0",
"get-port-please": "^3.1.2",
"http-proxy-middleware": "^3.0.3",
"pathe": "^1.1.2",
"picocolors": "^1.1.1",
"random-color": "^1.0.1",
"react": "19.0.0-rc-02c0e824-20241028",
"react-dom": "19.0.0-rc-02c0e824-20241028",
"sirv": "^3.0.0",
Expand Down
59 changes: 53 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 31 additions & 23 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,51 @@ import {
setNoDeprecation,
setNodeTitle,
} from './fishkit/node.js';
import { generate } from './generate';

interface RunOptions {
cwd: string;
name?: string;
template?: string;
}

async function run(cmd: string, options: RunOptions) {
async function run(cwd: string) {
const argv = yargsParser(process.argv.slice(2), {
alias: {
g: 'generate',
},
});
const cmd = argv._[0];
assert(cmd, 'Command is required');
switch (cmd) {
case 'create':
const { create } = await import('./create.js');
return create(options);
return create({
cwd: cwd,
name: argv.name,
template: argv.template,
});
case 'build':
const { build } = await import('./build.js');
return build({
cwd: options.cwd,
config: await loadConfig({ cwd: options.cwd }),
cwd,
config: await loadConfig({ cwd }),
});
case 'dev':
const { dev } = await import('./dev.js');
return dev({
cwd: options.cwd,
config: await loadConfig({ cwd: options.cwd }),
cwd,
config: await loadConfig({ cwd }),
});
case 'preview':
const { preview } = await import('./preview.js');
return preview({
cwd: options.cwd,
config: await loadConfig({ cwd: options.cwd }),
cwd,
config: await loadConfig({ cwd }),
});
case 'generate':
const type = argv._[1] as string;
const name = argv._[2] as string;
assert(type, 'Type is required');
assert(name, 'Name is required');
return generate({
cwd,
type,
name,
});
default:
throw new Error(`Unknown command: ${cmd}`);
Expand All @@ -46,15 +62,7 @@ setNoDeprecation();
checkVersion(MIN_NODE_VERSION);
setNodeTitle(FRAMEWORK_NAME);

const argv = yargsParser(process.argv.slice(2));
const cmd = argv._[0];

assert(cmd, 'Command is required');
run(cmd as string, {
cwd: process.cwd(),
name: argv._[1] as string | undefined,
template: argv.template as string | undefined,
}).catch((err) => {
run(process.cwd()).catch((err) => {
console.error(err.message);
process.exit(1);
});
60 changes: 60 additions & 0 deletions src/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import assert from 'assert';
import fs from 'fs-extra';
import path from 'path';
// @ts-ignore
import randomColor from 'random-color';

interface GenerateOptions {
cwd: string;
type: string;
name: string;
}

export function generate(opts: GenerateOptions) {
if (opts.type === 'page') {
return generatePage(opts);
}
}

function generatePage(opts: GenerateOptions) {
const pagesDir = path.join(opts.cwd, 'src/pages');
const pageName = opts.name;
const pagePath = path.join(pagesDir, `${pageName}.tsx`);
const styleModulePath = path.join(pagesDir, `${pageName}.module.less`);

assert(
!fs.existsSync(pagePath) && !fs.existsSync(styleModulePath),
`Page ${pageName} already exists.`,
);

fs.ensureDirSync(pagesDir);

const componentName = pageName.charAt(0).toUpperCase() + pageName.slice(1);
const pageContent = `import React from 'react';
import { createFileRoute } from '@umijs/tnf/router';
import styles from './${pageName}.module.less';
export const Route = createFileRoute('/${pageName}')({
component: ${componentName},
});
function ${componentName}() {
return (
<div className={styles.container}>
<h3>Welcome to ${componentName} Page!</h3>
</div>
);
}
`;

const styleContent = `.container {
color: ${randomColor().hexString()};
}
`;

fs.writeFileSync(pagePath, pageContent);
fs.writeFileSync(styleModulePath, styleContent);

console.log(`Generated page at: ${pagePath}`);
console.log(`Generated styles at: ${styleModulePath}`);
}

0 comments on commit c1dbe5a

Please sign in to comment.