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

Prepare for bundling #2087

Merged
merged 48 commits into from
May 23, 2024
Merged

Prepare for bundling #2087

merged 48 commits into from
May 23, 2024

Conversation

isaacroldan
Copy link
Contributor

@isaacroldan isaacroldan commented May 7, 2024

WHY are these changes introduced?

We plan to bundle the hydrogen package into shopify/cli. To do that we need to solve some peerDependencies imports.

WHAT is this pull request doing?

  • Import peerDependencies like Vite or Remix from the hydrogen project folder, even if the CLI is installed globally. We use require.resolve to find them.
  • Update cli-kit and oclif to latests versions
  • Change some assets folders so that they are generated in a way that works for the bundled output.

HOW to test your changes?

Post-merge steps

Checklist

  • I've read the Contributing Guidelines
  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've added a changeset if this PR contains user-facing or noteworthy changes
  • I've added tests to cover my changes
  • I've added or updated the documentation

Copy link
Contributor

shopify bot commented May 7, 2024

Oxygen deployed a preview of your prepare-for-bundling-2 branch. Details:

Storefront Status Preview link Deployment details Last update (UTC)
third-party-queries-caching ✅ Successful (Logs) Preview deployment Inspect deployment May 23, 2024 4:07 AM
Skeleton (skeleton.hydrogen.shop) ✅ Successful (Logs) Preview deployment Inspect deployment May 23, 2024 4:07 AM
optimistic-cart-ui ✅ Successful (Logs) Preview deployment Inspect deployment May 23, 2024 4:07 AM
vite ✅ Successful (Logs) Preview deployment Inspect deployment May 23, 2024 4:07 AM
subscriptions ✅ Successful (Logs) Preview deployment Inspect deployment May 23, 2024 4:07 AM
custom-cart-method ✅ Successful (Logs) Preview deployment Inspect deployment May 23, 2024 4:07 AM

Learn more about Hydrogen's GitHub integration.

Copy link
Contributor

@frandiox frandiox left a comment

Choose a reason for hiding this comment

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

🎉 It seems to be working well with the import/resolve trick, both local and global versions.

I've pushed a few commits to update package-lock and sync some other dependencies. Also left a few comments.

Comment on lines 106 to 107
const vitePath = require.resolve('vite', {paths: [root]});
const viteNodePath = joinPath(vitePath, '..', 'dist', 'node', 'index.js');
Copy link
Contributor

Choose a reason for hiding this comment

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

It makes me a bit nervous relying on package internal paths to resolve ESM.
Would it work if we just strip the last part of the path until ..../node_modules/vite so that import(...) resolves according to their own package.json? Or maybe that doesn't work?

Eventually we should we start requiring Node 20.6, which already supports import.meta.resolve(...).

Alternatively, we could rely on --experimental-import-meta-resolve flag for lower versions of Node (this returns a promise). We can restart the process to add this flag automatically like we do for --experimental-vm-modules: https://github.com/Shopify/hydrogen/blob/main/packages/cli/src/hooks/init.ts#L5

There's also a ponyfill but I haven't tried it: https://github.com/wooorm/import-meta-resolve

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the reason I had to do this is that vite has this export config:

"exports": {
    ".": {
      "import": {
        "types": "./dist/node/index.d.ts",
        "default": "./dist/node/index.js"
      },
      "require": {
        "types": "./index.d.cts",
        "default": "./index.cjs"
      }

When you use import it correctly uses the node one. When you use require it imports the cjs version.

If you try to import('{path}/node_modules/vite') it doesn't work:

│  Directory import '/Users/isaac/Projects/hydronext/node_modules/vite' is not   │
│  supported resolving ES modules imported from /Users/isaac/src/github.com/Sho  │
│  pify/hydrogen/packages/cli/dist/commands/hydrogen/build.js                    │
│  Did you mean to import                                                        │
│  /Users/isaac/Projects/hydronext/node_modules/vite/dist/node/index.js?         │

How would this import-meta-resolve help us 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.

Tried with

await import.meta.resolve?.('vite', root)

And it resolves it in the current directory and not in root 🤔

Another alternative could be this:

  const vitePath = require.resolve('vite', {paths: [root]});
  const vitePackageJson = await findUpAndReadPackageJson(vitePath) as {content: {[key: string]: any}, path: string};
  const viteNodeIndexFile = vitePackageJson.content.exports?.['.'].import.default
  const viteNodePath = joinPath(dirname(vitePackageJson.path), viteNodeIndexFile)

Load the package json and find the correct import there.

We could extract this so it's not repeated in many places and can be called like importViteFrom(root) or findVitePathFrom(root)

Copy link
Contributor

Choose a reason for hiding this comment

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

And it resolves it in the current directory and not in root 🤔

So I just learned something: the second parameter is ignored in the Node 20.6 (backproted to 18.19 actually) implementation to be spec compliant.
If you want the second param to work, you need to run with NODE_OPTIONS="--experimental-import-meta-resolve" h2 dev, which is an experimental feature. In this case we can't use it unless we add this flag automatically as mentioned in my previous comment. Perhaps not worth it for now.

Load the package json and find the correct import there.

I think this one would be safer, yes. The exports field can also be changed (['.'].import.default: string vs ['.'].import: string vs ['.'].default: string) but I guess we can check the common paths for ESM?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this one would be safer, yes. The exports field can also be changed (['.'].import.default: string vs ['.'].import: string vs ['.'].default: string) but I guess we can check the common paths for ESM?

Should we go with this approach? I guess we could have some kind of utility importLocal('...', {esm: true, from: '...'}) or similar that checks exports if available in the package, or fallback to module, then main etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, i'll try to do that :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've updated all the imports, let me know what you think

'hydrogen:setup:vite': SetupVite,
};

export default COMMANDS;
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 benefit of listing commands manually? Perf?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The CLI needs to explicitly import all commands from bundled dependencies, once bundled hydrogen won't act as a "plugin" anymore. The easiest way to do this is to export a list of all commands.

`${outDir}/${GENERATOR_TEMPLATES_DIR}/${GENERATOR_STARTER_DIR}`,
`${outDir}/lib/${GENERATOR_TEMPLATES_DIR}/${GENERATOR_STARTER_DIR}`,
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason to move the generated folder from dist/generator-templates to dist/lib/generator-templates? Doesn't it work at the root in global CLI?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nop, in the bundled CLI everything is at the root so we can't go look for anything at ../ (which is what we were doing for the generator templates here).

In order to look for them at ./, I had to put them inside lib, that way the import will work both in development and bundled.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I see.

There's also a generated dist/virtual-routes folder created at build time, which is referenced in src/lib/virtual-routes.ts also with ... Do we need to change that one too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I missed that one, but probably yes, where is that imported? what command do I need to run to test if it works?

Copy link
Contributor

Choose a reason for hiding this comment

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

This is only used for the classic remix compiler. Try npm run dev in examples/classic-remix. Then the routes /subrequest-profiler and /graphiql should be added dynamically from that folder.

The code is in lib/classic-compiler/dev.ts and lib/virtual-routes.ts. The actual virtual-routes folder is copied from packages/hydrogen at build time in packages/cli/tsup.config.ts.

packages/cli/package.json Outdated Show resolved Hide resolved
Iben1993

This comment was marked as off-topic.

Comment on lines +3 to -5
import {copy as copyWithFilter, createSymlink} from 'fs-extra/esm';
import {
inTemporaryDirectory,
copyFile,
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated but it would be nice to make filter available in cli-kit's copyFile.

@isaacroldan isaacroldan marked this pull request as ready for review May 22, 2024 09:07

This comment has been minimized.

Copy link
Contributor

@frandiox frandiox left a comment

Choose a reason for hiding this comment

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

Looking good! Let's try to test this in a new experimental release asap.

@frandiox frandiox merged commit 65239c7 into main May 23, 2024
13 checks passed
@frandiox frandiox deleted the prepare-for-bundling-2 branch May 23, 2024 04:40
michenly pushed a commit that referenced this pull request May 24, 2024
* Explicitly export CLI commands

* Commit dist folder

* Move peerDependencies to dependencies

* Improve prettier imports

* Some cleanup

* Fix prettier import

* Import vite with a dynamic path

* Fix versions

* Fix package.json

* install remix

* dynamic import for codegen

* dynamic import for hydrogen-codegen

* dynamic import for mini-oxygen

* Build hydrogen

* Dynamic import for graphql-config

* Dynamic import for remix-run

* Remove dist

* some cleanup

* Update package-lock.json

* Update package-lock.json

* Apply prettier format

* Update some functions

* Fix tests

* Format

* Fix more dynamic imports

* Fix more dynamic imports

* Some cleanup

* format

* Upgrade oclif and cli-kit

* Update cli version in templates

* Update minimum oxygen-cli version to bump oclif/core dep

* Dedup package-lock.json

* Update packages/cli/package.json

Co-authored-by: Fran Dios <frankdiox@gmail.com>

* Create import-utils file to extract all custom imports

* Extract all local imports to common file

* Format code

* Update package-lock.json

* Remove unnecessary overrides

* Clean unused imports

* Copy virtual routes inside lib

* Fix CLI tests

* Fix package-lock

* Minor refactor

* Changesets

---------

Co-authored-by: Fran Dios <fran.dios@shopify.com>
Co-authored-by: Fran Dios <frankdiox@gmail.com>
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.

None yet

3 participants