-
-
Notifications
You must be signed in to change notification settings - Fork 287
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
Conversation
packages/create-toolpad-app/index.ts
Outdated
console.log(`Creating a new MUI Toolpad project in ${chalk.blue(name.projectName)}`); | ||
try { | ||
await fs.mkdir(name.projectName); | ||
process.chdir(name.projectName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
packages/create-toolpad-app/index.ts
Outdated
}; | ||
|
||
// Create a new directory and initialize a new project | ||
const scaffoldProject = async () => { |
There was a problem hiding this comment.
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
const scaffoldProject = async () => { | |
const scaffoldProject = async (name: string): Promise<void> => { |
and calling inquirer
before calling this function would make more sense to me.
packages/create-toolpad-app/index.ts
Outdated
return name.projectName; | ||
} catch (error) { | ||
// Directory exists, verify if it is empty to continue | ||
if (!isFolderEmpty(path.join(process.cwd(), name.projectName), name.projectName)) { |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 = [ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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:`); |
There was a problem hiding this comment.
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.
packages/create-toolpad-app/index.ts
Outdated
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"type": "module", |
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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/", |
There was a problem hiding this comment.
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/", |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// process.chdir(projectName); |
|
||
if (files.length > 0) { | ||
// eslint-disable-next-line no-console | ||
console.log(`The directory ${chalk.green(name)} is non-empty.`); |
There was a problem hiding this comment.
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.
Great work! |
CTA.mov