Skip to content

modular rename command#1163

Merged
cristiano-belloni merged 27 commits intomainfrom
feature/add-rename
Jan 5, 2022
Merged

modular rename command#1163
cristiano-belloni merged 27 commits intomainfrom
feature/add-rename

Conversation

@cristiano-belloni
Copy link
Contributor

@cristiano-belloni cristiano-belloni commented Dec 8, 2021

Done:

  1. Move old package directory to new package directory - We decided with @cangarugula that we don't want to do this as it's ambiguous and directory and package name are not necessarily coupled - see also docs/commands/rename.md
  2. Change package name in package.json
  3. Change dependency name in depending packages' package.json - not needed.
  4. Re-write imports in depending packages' source files
  5. Add logs
  6. Write tests
  7. Add docs
  8. Made action atomic

@changeset-bot
Copy link

changeset-bot bot commented Dec 8, 2021

🦋 Changeset detected

Latest commit: 40ad365

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
modular-scripts Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coveralls
Copy link
Collaborator

coveralls commented Dec 8, 2021

Coverage Status

Coverage decreased (-0.5%) to 28.282% when pulling 40ad365 on feature/add-rename into c25c128 on main.

@cristiano-belloni cristiano-belloni marked this pull request as ready for review December 13, 2021 16:26
@cristiano-belloni cristiano-belloni changed the title Rename command modular rename command Dec 13, 2021
logger.debug(`Checking for existence of ${oldPackageName} in workspace.`);
const oldPackage = workspace.find(
([packageName]) => packageName === oldPackageName,
)?.[1];
Copy link
Contributor

Choose a reason for hiding this comment

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

You shouldn't need to flatten this because the package names are saved as keys returned from getWorkspaceInfo that you can access via bracket notation to check if they exist in the modular workspace.

{ "app": { "location": "packages/app", "workspaceDependencies": [], "mismatchedWorkspaceDependencies": [], "type": "app", "public": false }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

throw new Error(`Package ${oldPackageName} not found.`);
}
logger.debug(`Checking for collision with ${newPackageName} in workspace.`);
if (workspace.find(([packageName]) => packageName === newPackageName)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


// Rename the directory. Do it first because this fails if there's a collision and we don't want to clean up later
const newPackageLocation = path.join(
getModularRoot(),
Copy link
Contributor

Choose a reason for hiding this comment

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

You call getModularRoot multiple times in this function. Can you store this at the top when you first need it and use that instead of making calls again?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cangarugula It's memoized to allow calling it without performance penalty. I can hoist it, but everywhere else we use the "just call it" pattern, which imho is a bit more readable.

// Rename the directory. Do it first because this fails if there's a collision and we don't want to clean up later
const newPackageLocation = path.join(
getModularRoot(),
path.join(oldPackage.location, '..'),
Copy link
Contributor

Choose a reason for hiding this comment

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

If the newPackageName is scoped, i.e. @app/view, you'll need to create the new package location either nested respective to its scope (packages/app/view) or as a param-cased directory (packages/app-view). I'm unsure of which should be the default - let's have a think about this. We may need a flag here to determine this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, that needs a bit more work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, not renaming directories as discussed.

)
).filter((pkgJsonInfo) =>
dependencyTypes.some(
(depField) => pkgJsonInfo.json[depField]?.[oldPackageName],
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the use case here? If a package is using another package in the same monorepo, they shouldn't need to specify it as a dependency in their package.json. The one case I can think of is if they want to specify an older version of the dependency, in which case, you wouldn't want to change it to the new package name. Maybe I'm missing a use case here.

Copy link
Contributor Author

@cristiano-belloni cristiano-belloni Dec 14, 2021

Choose a reason for hiding this comment

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

If a package is using another package in the same monorepo, they shouldn't need to specify it as a dependency in their package.json

Don't they need to specify the dependency in their package.json to get the other package symlinked? I'm fairly new to yarn workspaces but that's what the documentation example says: https://classic.yarnpkg.com/lang/en/docs/workspaces/#toc-how-to-use-it (note that it's not necessary to build package-a, if you don't need it outside the monorepo you just point main or module or exports to src)

There's always the case that package-b just imports from package-a's source using a relative path (eg import libA from "../package-a/src/index.js"), but then what's the advantage of having workspaces / a monorepo (ie decoupling packages etc)?

Copy link
Contributor

Choose a reason for hiding this comment

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

They don't need to specify the dependency to use the package immediately. Because we set "workspaces": ["packages/**] and we call "yarn" after we create a new package with /packages, yarn creates a symlink to the local package in your node_modules, which can be imported/required using its package name.

But they would need to add it explicitly is if they wanted to externalize the dependency from the build, which case would be to published version that can be installed from the registry. But I can also see the value of doing it anyways just in case they do have the dependency there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, removed renaming of dependencies in package.jsons (I was used to rushjs, where you have to specify internal dependencies. Good to know!)

.gitignore Outdated
packages/nested
packages/sample-library-package
packages/sample-depending-package
packages/sample-library-renamed-package
Copy link
Contributor

Choose a reason for hiding this comment

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

let's add a scoped and nested example - which will be the majority of apps for our teams

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now that we don't actually rename directories, do we still need this? Wouldn't like to pollute the repo too much.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need the scoped examples anymore. And we won't need packages/sample-library-renamed-package because we aren't changing the directory name anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, done.

});
await project.save();
}),
);
Copy link
Contributor

Choose a reason for hiding this comment

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

If you change the package name in the package.json, you'll need to do a execa.sync('yarnpkg') to update the the name of the symlink in node_modules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

"modular-scripts": minor
---

Add "modular rename" command
Copy link
Contributor

@cangarugula cangarugula Jan 5, 2022

Choose a reason for hiding this comment

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

Let's add a tiny summary of what rename will do so that the release notes generated will have a bit more info on this

Copy link
Contributor Author

@cristiano-belloni cristiano-belloni Jan 5, 2022

Choose a reason for hiding this comment

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

Done, but still really tiny (a more detailed description will be added in the next release notes)

.gitignore Outdated
packages/nested
packages/sample-library-package
packages/sample-depending-package
packages/sample-library-renamed-package
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need the scoped examples anymore. And we won't need packages/sample-library-renamed-package because we aren't changing the directory name anymore.

});

program
.command('rename <old-package-name> <new-package-name>')
Copy link
Contributor

Choose a reason for hiding this comment

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

We use camel case for command variables some places and pascal case in others. Since our options are camel cased, maybe we could stick with that format?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


interface PackageJson extends Partial<DependencyObject> {
name: string;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You should also be able to get those dependencty types from import { CoreProperties } from '@schemastore/package'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, this was handy before, where I iterated on the depTypes const array and constructed the types from it, but it's not needed now. Done.

}

try {
logger.debug(`Checking for existence of ${oldPackageName} in workspace.`);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should check for the existence and collisions before we ask people to stash their changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

);

logger.log(`Refreshing packages`);
execa.sync('yarnpkg');
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's silence the install and specific the cwd as modular root in case they're not in the root. execa.sync('yarnpkg', ['--silent'], { cwd: modularRoot })

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@cristiano-belloni cristiano-belloni merged commit e180686 into main Jan 5, 2022
@cristiano-belloni cristiano-belloni deleted the feature/add-rename branch January 5, 2022 15:13
@github-actions github-actions bot mentioned this pull request Jan 5, 2022
This was referenced Mar 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants