stackblitz / tutorialkit

TutorialKit by StackBlitz - Create interactive tutorials powered by the WebContainer API
https://tutorialkit.dev
MIT License
232 stars 22 forks source link

Tutorial created in workspace fails #235

Closed PhearZero closed 2 weeks ago

PhearZero commented 1 month ago

Describe the bug

It looks like vite is not resolving the dependencies correctly when it's in an npm workspace.

Error

Failed to resolve import "node_modules/astro/dist/transitions/swap-functions" from "node_modules/@tutorialkit/astro/dist/default/layouts/Layout.astro?v=c1a1fee0&astro&type=script&index=0&lang.ts". Does the file exist?

Link to a StackBlitz project which shows the error

https://github.com/phearzero/withastro-astro-ru7fip

Steps to reproduce

  1. npm init
  2. add packages/* to workspaces in package.json
  3. mkdir packages
  4. cd packages && npm create astro@latest -- --template starlight
  5. cd ../packages && npm create tutorial
  6. cd ../../ && npm install

If everything is properly deduplicated in the workspace, then tutorialkit is looking in the ./packages/tutorial/node_modules folder which only has the vite bundle.

Expected behavior

Ability to use in a workspace that includes a docs module which consumes the workspace packages

Screenshots

No response

Platform

Additional context

No response

AriPerkkio commented 1 month ago

The error seems to be coming from here:

https://github.com/stackblitz/tutorialkit/blob/bd0ca1a5d1eb6a17ec2fcd6d776fe68458fd3cd6/packages/astro/src/default/layouts/Layout.astro#L41

Nemikolh commented 1 month ago

@PhearZero Does ejecting the tutorial works in this setup? You can eject with:

npx @tutorialkit/cli eject --force

If not @AriPerkkio, I think we could probably use a virtual module for this and make it possible to customize the imported path via a config option. By config option, I mean an option to the tutorialkit astro integration.

PhearZero commented 1 month ago

@Nemikolh no luck, looks like a similar problem on the assertion here. I'll try to bypass it and test again

 ERROR  ./withastro-astro-ru7fip/packages/tutorial/node_modules/@tutorialkit/astro does not exists!

Edit: Was able to successfully resolve the path with import.meta.resolve('@tutorialkit/astro').replace('dist/index.js', '').replace('file://', ''). There may be more calls like this, first time using import meta resolve and it's nice! I'm getting more errors downstream but it successfully patched the package.json 🕺

 INFO  New dependencies added: @tutorialkit/runtime, @webcontainer/api, nanostores, @nanostores/react, kleur, @stackblitz/sdk. Install the new dependencies before proceeding.

Edit: Was able to eject my actual docs project then add it to the workspace, same error for resolving swap-functions.

AriPerkkio commented 3 weeks ago

We are waiting for a feature from Astro's side that allows us to remove the hacky private API solution from TutorialKit that is causing this bug.

Meanwhile you can use following work-around in your astro.config.ts:

import { createRequire } from 'node:module';
import { resolve } from 'node:path';
import tutorialkit from '@tutorialkit/astro';
import { defineConfig } from 'astro/config';

const require = createRequire(import.meta.url);
const astroDist = resolve(require.resolve('astro/package.json'), '..');
const swapFunctionEntry = resolve(astroDist, 'dist/transitions/swap-functions.js');

export default defineConfig({
  integrations: [tutorialkit()],

  vite: {
    resolve: {
      alias: {
        'node_modules/astro/dist/transitions/swap-functions': swapFunctionEntry,
      },
    },
  },
});
PhearZero commented 3 weeks ago

@AriPerkkio Would you want me to file an additional issue for the cli? I ran into a similar issue running eject in this assertion:

https://github.com/stackblitz/tutorialkit/blob/745be37ef20ae97d6ded221fca24670742981879/packages/cli/src/commands/eject/index.ts#L152

I was able to use import.meta.resolve instead of using createRequire, is there any reason to use require over the ESM resolver?

AriPerkkio commented 3 weeks ago

Sure, please file separate issues for bugs that are not related to this issue.

You can use import.meta.resolve if your NodeJS version supports that. As we are still supporting 18.18, I'm defaulting to recommending createRequire(...).resolve(...).

$ node test.mjs 
file:///x/y/z/repros/test.mjs:1
const pkg = import.meta.resolve("astro");
                        ^

TypeError: (intermediate value).resolve is not a function
    at file:///x/y/z/repros/test.mjs:1:25
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)

Node.js v18.18.0