-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
feat(core): add monorepo generator to convert from standalone projects #18245
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
d712335
to
cb0bf1e
Compare
cb0bf1e
to
d111be9
Compare
d111be9
to
fb0ef75
Compare
fb0ef75
to
8454d70
Compare
8454d70
to
de33ac7
Compare
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.
Copying over my slack reply just so it doesn't get lost:
Nice! We have a precedent for conversion generators starting with convert to make it clear it’s mutating existing stuff as its focus, so maybe convert-to-monorepo is preferable?
As Victor notes it’s going to be run very rarely so arguably clarity can be weighted above brevity because it’s not an ongoing source of friction to type?
I would worry
nx generate @nx/workspace:monorepo
could easily be confused with create-nx-workspace
de33ac7
to
d3411ee
Compare
d3411ee
to
5fcfd3e
Compare
5fcfd3e
to
80ee98a
Compare
9659577
to
7eb9b76
Compare
130eeef
to
f0ce95d
Compare
const nxJson = readNxJson(tree); | ||
nxJson.workspaceLayout = { | ||
// normalize paths without trailing slash | ||
appsDir: joinPathFragments(options.appsDir), | ||
libsDir: joinPathFragments(options.libsDir), | ||
}; | ||
|
||
updateNxJson(tree, nxJson); |
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.
Just add the directories and it will have the same effect. Do not write to nx.json.
This can move after the move.
- If we move an app, we also have to add the libs dir that the user wants
- If we move a lib, we don't actually have to do anything because moving the project will create the libs dir
"appsDir": { | ||
"type": "string", | ||
"description": "The directory where apps are placed.", | ||
"default": "apps", | ||
"x-prompt": "Where do you want to place your apps?" | ||
}, |
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.
Let's always pick apps
if the root project is an app. Do not prompt.
"libsDir": { | ||
"type": "string", | ||
"alias": "packagesDir", | ||
"description": "The directory where libs/packages are placed.", | ||
"default": "libs", | ||
"x-prompt": "Where do you want to place your libs/packages?" | ||
} |
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.
Constrain this to ['libs', 'packages']
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.
Turns out, we're restricted to apps-libs vs packages anyway, so removing all the prompts. i.e. you cannot have apps-packages.
maybeExtractEslintConfigIfRootProject(tree, project); | ||
await moveGenerator(tree, { | ||
projectName: project.name, | ||
destination: project.name, |
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.
Pass destinationRelativeToRoot
so that the destination is taken as is.
This turns into join(options.appsDir | options.libsDir, project.name)
mayebExtractTsConfigBase(tree); | ||
await maybeExtractJestConfigBase(tree); |
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.
All of the extract, should go into move
. Regardless of if we are moving from a monorepo or not, if a user moves the root app, we should do this stuff.
This could be refactored more later.
const relativeFromOriginalSource = relative(project.root, file); | ||
const newFilePath = join( | ||
schema.relativeToRootDestination, | ||
relativeFromOriginalSource | ||
); | ||
|
||
// Prevents moving the same file infinitely for root projects | ||
if (seen.has(file)) return; |
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 isn't needed anymore after the whitelist.
.relative(path.join(workspaceRoot, project.root), workspaceRoot) | ||
.split(path.sep) | ||
.join('/'); | ||
const oldRelativeRoot = |
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 can be reverted.
if (file === '.eslintrc.json') { | ||
continue; | ||
} | ||
if (!shouldUpdate(file)) continue; |
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 should go back to how it was.
expect(tree.exists('package.json')).toBeTruthy(); | ||
expect(tree.exists('README.md')).toBeTruthy(); | ||
expect(tree.exists('.gitignore')).toBeTruthy(); | ||
expect(tree.exists('other-lib/index.ts')).toBeTruthy(); |
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.
We should test that root config files are made
formatFiles, | ||
ProjectGraph, |
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.
Unneeded imports
f0ce95d
to
3841cab
Compare
3841cab
to
006c1ea
Compare
006c1ea
to
6a25f13
Compare
6a25f13
to
1541dd5
Compare
1541dd5
to
b2f3806
Compare
b2f3806
to
d49936f
Compare
d49936f
to
3f57363
Compare
3f57363
to
13f0b2c
Compare
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.
just a question
@@ -2842,6 +2842,15 @@ | |||
"path": "workspace/generators/remove", | |||
"type": "generator" | |||
}, | |||
{ | |||
"description": "Convert a Nx project to a monorepo.", |
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.
@ndcunningham Can you make this change in a follow up PR please?
This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request. |
This PR adds a new
@nx/workspace:monorepo
generator that converts standalone projects to a monorepo.For example:
Then users will see:
generator-monorepo.mp4
Test Cases
create-nx-workspace
without any changes). Test with React, Next.js, Angular, Node servers, TS.apps
andlibs
directories.packages/my-lib
orlibs/my-lib
already exists.Notes
apps
since there are workspace files such asnx.json
, or even custom files that users create that may or may not belong to the root project. The safest way to handle it is to whitelist the root files we do move, and leave the rest for users to handle.e2e
project is problematic since it is not easy to replace"e2e"
string in configuration files withapps/e2e
without messing options like"target": "e2e"
that should be left untouched. We may need to handle these cases specifically.