Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add create-toolpad-app CLI #1700

Merged
merged 141 commits into from
Mar 20, 2023
Merged

Add create-toolpad-app CLI #1700

merged 141 commits into from
Mar 20, 2023

Conversation

bharatkashyap
Copy link
Member

@bharatkashyap bharatkashyap commented Feb 22, 2023

CTA.mov

console.log(`Creating a new MUI Toolpad project in ${chalk.blue(name.projectName)}`);
try {
await fs.mkdir(name.projectName);
process.chdir(name.projectName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
process.chdir(name.projectName);

Can this be avoided? e.g. by passing cwd to execa instead. I feel like this could lead to weird issues where half the program is working in a certain working dir, and the other half in another. Moving code around could become awkward

};

// Create a new directory and initialize a new project
const scaffoldProject = async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nit, but nothing about the name scaffoldProject suggests it would be returning a string or what that string means. It feels like

Suggested change
const scaffoldProject = async () => {
const scaffoldProject = async (name: string): Promise<void> => {

and calling inquirer before calling this function would make more sense to me.

return name.projectName;
} catch (error) {
// Directory exists, verify if it is empty to continue
if (!isFolderEmpty(path.join(process.cwd(), name.projectName), name.projectName)) {
Copy link
Member

@Janpot Janpot Mar 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, you read process.cwd() once and pass it around. Especially when you'll be doing process.chdir in some places.
The purer a functions is, the easier to debug and test.

console.log();
for (const file of conflicts) {
try {
const stats = fs.lstatSync(path.join(root, file));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid sync methods

];

const conflicts = fs
.readdirSync(root)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid sync methods

import path from 'path';

export function isFolderEmpty(root: string, name: string): boolean {
const validFiles = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we really going to curate a list with random files? Why not just be strict? empty == no files?

Copy link
Member Author

@bharatkashyap bharatkashyap Mar 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I imagined that we could rely on the list curated by https://github.com/vercel/next.js/blob/canary/packages/create-next-app/helpers/is-folder-empty.ts but it might make sense to keep it simple and follow the strict definition of an empty folder to begin with

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that could make sense then

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we leave it in, then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you wish


if (conflicts.length > 0) {
// eslint-disable-next-line no-console
console.log(`The directory ${chalk.green(name)} contains files that could conflict:`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to present itself as a reusable utility function isFolderEmpty, but then proceeds to do very specific logic for certain files, adds logging, etc... This function is not a reusable utility. I'd remove this file and colocate the code where you are using it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For package structure I'd propose to use a src folder, just like the other projects. Also not sure whether there is real benefit to add a utils folder in a project that has 3 source files

"author": "Toolpad Team",
"license": "MIT",
"bin": {
"create-toolpad-app-test": "./dist/index.js"
Copy link
Member

@Janpot Janpot Mar 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"create-toolpad-app-test": "./dist/index.js"
"create-toolpad-app": "./dist/index.js"

Also, does this file have execute permissions? I didn't think tsc dealt with that. In the other package we use a top level javascript file with execute permissions that imports from the dist folder

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, does this file have execute permissions?

What do you mean by this exactly/How do I test this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which command do you use to test the cli at the moment?

Copy link
Member Author

@bharatkashyap bharatkashyap Mar 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In development, I run the built file from the dist folder in a separate folder through node; to test the production version, I publish the package and run create toolpad-app to test the flow

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, it looks like npm automatically sets the correct file permissions when you use the bin field. I didn't know that. Maybe we should do the same for the @mui/toolpad cli later on.

"files": [
"dist"
],
"type": "module",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"type": "module",

?

Copy link
Member Author

@bharatkashyap bharatkashyap Mar 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this I get

SyntaxError: Cannot use import statement outside a module

errors when running the compiled .js file,

Or alternatively, if compiling to es5, a

Error [ERR_REQUIRE_ESM]: require() of 
ES Module MUI/mui-studio/packages/create-toolpad-app/node_modules/chalk/source/index.js 
from MUI/mui-studio/packages/create-toolpad-app/dist/index.js not supported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this by dynamically importing all the ES modules (chalk, inquirer and execa)

],
"type": "module",
"scripts": {
"dev13": "tsc -w -p ./tsconfig.json --outDir ./dist/",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can outDir go in tsconfig.json?

"type": "module",
"scripts": {
"dev13": "tsc -w -p ./tsconfig.json --outDir ./dist/",
"prerelease": "rimraf ./dist/",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    "prebuild": "rimraf ./dist/",
    "build": "tsc -p ./tsconfig.json -outDir ./dist/",

Let's use the same script names as in @mui/toolpad-core and @mui/toolpad-components?

"dependencies": {},
"devDependencies": {
"@types/inquirer": "^9.0.3",
"chalk": "^5.2.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these will need to go in dependencies when we don't use ncc

Copy link
Member

@Janpot Janpot Mar 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does @types/inquirer have to go in dependencies as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, devDependencies should be fine

console.log(`Creating a new MUI Toolpad project in ${chalk.blue(projectName)}`);
try {
await fs.mkdir(projectName);
// process.chdir(projectName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// process.chdir(projectName);


if (files.length > 0) {
// eslint-disable-next-line no-console
console.log(`The directory ${chalk.green(name)} is non-empty.`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: does it make sense to move this logging to the consumer of isFolderEmpty? The function name doesn't suggest it will have side-effects.

@Janpot
Copy link
Member

Janpot commented Mar 19, 2023

Great work!

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Mar 19, 2023
Base automatically changed from direction-13 to master March 20, 2023 08:03
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Mar 20, 2023
@Janpot Janpot enabled auto-merge (squash) March 20, 2023 08:35
@Janpot Janpot merged commit efd6638 into master Mar 20, 2023
@Janpot Janpot deleted the create-toolpad-app branch March 20, 2023 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Infrastructure work going on behind the scenes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants