Skip to content

Commit

Permalink
Support create command to create a new farm project (#29)
Browse files Browse the repository at this point in the history
* feat: add create command to create a new farm project

* chore: update pnpm lockfile
  • Loading branch information
wre232114 authored Feb 20, 2023
1 parent b7351ab commit d1c4765
Show file tree
Hide file tree
Showing 16 changed files with 241 additions and 25 deletions.
1 change: 1 addition & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
id: changesets
uses: changesets/action@v1
with:
version: npx changeset version && pnpm i
publish: npx changeset publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/src/create/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import path from 'node:path';
import { copyFiles, TEMPLATES_DIR } from '../utils.js';

const TEMPLATE_REACT = path.join(TEMPLATES_DIR, 'react');

export async function create(): Promise<void> {
const dest = path.join(process.cwd(), 'farm-react');

copyFiles(TEMPLATE_REACT, dest);
}
5 changes: 5 additions & 0 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { start, build } from '@farmfe/core';
import { cac } from 'cac';
import { create } from './create/index.js';
import { COMMANDS } from './plugin/index.js';

const cli = cac();
Expand All @@ -23,6 +24,10 @@ cli.command('build', 'Compile the project in production mode').action(() => {
});
});

cli.command('create', 'Create a new project').action(() => {
create();
});

cli.command('').action(() => {
cli.outputHelp();
});
Expand Down
29 changes: 6 additions & 23 deletions packages/cli/src/plugin/create.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import path from 'path';
import walk from 'walkdir';
import inquirer from 'inquirer';
import chalk from 'chalk';
import { fileURLToPath } from 'url';
import { copyFiles, TEMPLATES_DIR } from '../utils.js';

export interface CreateArgs {
npmName?: string;
structName?: string;
dir?: string;
}

const TEMPLATES_DIR = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'../../templates/rust-plugin'
);
const TEMPLATE_PLUGIN = path.join(TEMPLATES_DIR, 'rust-plugin');
const TEMPLATE_NPM_NAME = '<FARM-RUST-PLUGIN-NPM-NAME>';
const TEMPLATE_STRUCT_NAME = '<FARM-RUST-PLUGIN-STRUCT-NAME>';

Expand Down Expand Up @@ -56,22 +51,10 @@ export async function create(args: CreateArgs): Promise<void> {

const dest = path.join(process.cwd(), dir);

walk(TEMPLATES_DIR, { sync: true }, (p, stat) => {
if (stat.isFile()) {
const content = readFileSync(p).toString();
const newContent = content
.replace(new RegExp(TEMPLATE_NPM_NAME, 'g'), npmName)
.replace(new RegExp(TEMPLATE_STRUCT_NAME, 'g'), structName);

const relativePath = path.relative(TEMPLATES_DIR, p);
const destPath = path.join(dest, relativePath);

if (!existsSync(path.dirname(destPath))) {
mkdirSync(path.dirname(destPath), { recursive: true });
}

writeFileSync(destPath, newContent);
}
copyFiles(TEMPLATE_PLUGIN, dest, (content) => {
return content
.replace(new RegExp(TEMPLATE_NPM_NAME, 'g'), npmName)
.replace(new RegExp(TEMPLATE_STRUCT_NAME, 'g'), structName);
});

console.log(chalk.green(`Plugin created successfully in ${dest}`));
Expand Down
32 changes: 32 additions & 0 deletions packages/cli/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import walkdir from 'walkdir';

export const TEMPLATES_DIR = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'..',
'templates'
);

export function copyFiles(
source: string,
dest: string,
callback?: (content: string) => string
): void {
walkdir(source, { sync: true }, (p, stat) => {
if (stat.isFile()) {
const content = readFileSync(p).toString();
const newContent = callback?.(content) ?? content;

const relativePath = path.relative(source, p);
const destPath = path.join(dest, relativePath);

if (!existsSync(path.dirname(destPath))) {
mkdirSync(path.dirname(destPath), { recursive: true });
}

writeFileSync(destPath, newContent);
}
});
}
19 changes: 19 additions & 0 deletions packages/cli/templates/react/farm.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defineFarmConfig } from '@farmfe/core/dist/node/config';

export default defineFarmConfig({
compilation: {
input: {
index: './index.html',
},
resolve: {
symlinks: true,
mainFields: ['module', 'main', 'customMain'],
},
output: {
path: './build',
},
},
server: {
hmr: true,
},
});
14 changes: 14 additions & 0 deletions packages/cli/templates/react/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script>var process = { env: { NODE_ENV: 'development' } }</script>
<script src="./src/index.tsx"></script>
</body>
</html>
18 changes: 18 additions & 0 deletions packages/cli/templates/react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@farmfe-examples/react",
"version": "0.0.0",
"dependencies": {
"react": "18",
"react-dom": "18"
},
"devDependencies": {
"@farmfe/cli": "*",
"@farmfe/core": "*",
"@types/react": "18",
"@types/react-dom": "18",
"react-refresh": "^0.14.0"
},
"scripts": {
"start": "farm start"
}
}
20 changes: 20 additions & 0 deletions packages/cli/templates/react/src/comps/counter-button/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.counter-button {
width: 200px;
height: 50px;
border: none;
background-color: green;
color: white;
font-size: 30px;
line-height: 50px;
border-radius: 10px;
cursor: pointer;
}

.counter-button:hover {
background-color: lightgreen;
}

.disable {
background-color: #999;
color: #333;
}
57 changes: 57 additions & 0 deletions packages/cli/templates/react/src/comps/counter-button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useEffect, useState } from 'react';

import './index.css'

const COUNT_DOWN = 60;
const BUTTON_TEXT = 'Start Count';

export function CounterButton() {
const [count, setCount] = useState(COUNT_DOWN);
const [text, setText] = useState(BUTTON_TEXT);
const [timer, setTimer] = useState(null as null | number);
const [pause, setPause] = useState(false);

useEffect(() => {
return () => {
if (timer) {
clearInterval(timer);
}
}
}, [timer]);

const countdown = () => {
console.log(timer, pause, count, text);
setCount(count => {
if (count == 0) {
clearInterval(timer as number);
setText(BUTTON_TEXT);
return 0;
}

setText(`${count - 1}`);
return count - 1;
});
};

return <button className='counter-button' onClick={() => {
if (timer && pause === false) {
setPause(true);
setText('Pause')

clearInterval(timer);
return;
} else if (pause === true) {
setPause(false);
setText(`${count}`);

setTimer(setInterval(countdown, 1000));
return;
}

console.log(timer, pause, count, text);
const t = setInterval(countdown, 1000);

setText(`${COUNT_DOWN}`);
setTimer(t);
}}>{text}</button>
}
8 changes: 8 additions & 0 deletions packages/cli/templates/react/src/comps/description/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';

export function Description() {
return <div className='description'>
<p>Farm is a supper fast building engine written in rust. 🔥 </p>
<p>Visit https://github.com/farm-fe/farm for details</p>
</div>
}
8 changes: 8 additions & 0 deletions packages/cli/templates/react/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
import { createRoot } from 'react-dom/client';

import { Main } from './main';
const container = document.querySelector('#root')!;
const root = createRoot(container);

root.render(<Main />)
23 changes: 23 additions & 0 deletions packages/cli/templates/react/src/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#root {
background-color: whitesmoke;
font-size: 24px;
height: 300px;
}

.button-wrapper {
padding-top: 100px;
/* color: red; */
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
}

.description {
margin-top: 10px;
color: #333;
font-size: 16px;
margin: 0;
padding: 0;
text-align: center;
}
17 changes: 17 additions & 0 deletions packages/cli/templates/react/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { CounterButton } from './comps/counter-button';
import { Description } from './comps/description';
import './main.css';

export function Main() {
return (
<>
<div className='button-wrapper'>
<CounterButton />
</div>
<div>
<Description />
</div>
</>
);
}
1 change: 1 addition & 0 deletions packages/cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"declaration": false
},
"exclude": ["node_modules"],
"include": ["src/**/*"],
"references": [
{
"path": "../core/tsconfig.build.json"
Expand Down
4 changes: 2 additions & 2 deletions pnpm-lock.yaml

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

0 comments on commit d1c4765

Please sign in to comment.