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

prevent loading of illegal modules in the browser #7507

Merged
merged 32 commits into from
Nov 10, 2022

Conversation

Rich-Harris
Copy link
Member

@Rich-Harris Rich-Harris commented Nov 4, 2022

Closes #6700. Closes #7288. Right now, we prevent people from importing illegal modules ($env/[type]/private, $lib/server/** and **/*.server.{ext}) by analysing the module graph during SSR. This is a flawed approach for a variety of reasons:

  • It doesn't account for systems like telefunc, which transform modules differently between SSR and non-SSR modes such that the dangerous import declarations are removed
  • it means you only get the error when you hit a page directly, not when you soft-navigate to a page. (I was surprised to realise that this morning!)
  • it applies even to pages that have csr = false

A much simpler approach is to simply prevent the modules in question from being imported in the browser at dev time. We can do this by adding a guard in a load hook that throws if the relevant conditions are met. (At build time we keep the existing graph analysis.)

There's a couple of minor drawbacks: we don't get the import chain, just the module ID, and the error overlay is dismissable. I think these trade-offs are well worth it.

A nice bonus is that we can get rid of the code for traversing the Vite module graph. Since we now only need to worry about the Rollup module graph, this also means we can get rid of a layer of indirection (sorry @tcc-sejohnson, it was good code! but no longer needed). That part is a WIP.

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. All changesets should be patch until SvelteKit 1.0

@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2022

🦋 Changeset detected

Latest commit: d79cc59

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

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Patch

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

@elliott-with-the-longest-name-on-github
Copy link
Contributor

As long as we're retaining the same graph analysis in build as we were before I see no problem with this -- I wanted to do this when we originally implemented the feature, but just couldn't figure out how. Please ping me when this is ready-er for merge -- happy to review 😁

@Rich-Harris
Copy link
Member Author

Ok I think this is ready now, marking it as such and crossing my fingers that the tests pass. One wrinkle: if the Vite error overlay appears before hydration, it will get nuked if %sveltekit.body% isn't wrapped in an element below the <body>, so I had to make that change to the test app.

I almost wonder if we should enforce that, since it's a bit of a footgun otherwise.

@tcc-sejohnson would be grateful if you do get a chance to review! The build stuff should be basically identical

@Rich-Harris
Copy link
Member Author

alright, things finally seem to be working again. @tcc-sejohnson if you have the bandwidth to take another look since you requested changes, that would be great — looking forward to getting this one merged 🙏

@lukaszpolowczyk
Copy link
Contributor

Anecdotally, I've seen a good number of people in the Discord that remove the div wrapper for "easier" styling, so... might be a good idea to try to find a way.

@tcc-sejohnson I in one project added to this div a style="display: contents;", and it was enough for me.

I don't know if that can cause a problem, but I haven't noticed any.

Comment on lines +42 to +44
function follow(id, chain) {
if (seen.has(id)) return;
seen.add(id);

Choose a reason for hiding this comment

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

nothing is wrong here; I just wanted you to see what the heck GitHub thinks these lines correlate to in the original diff

Copy link
Member Author

@Rich-Harris Rich-Harris Nov 10, 2022

Choose a reason for hiding this comment

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

GitHub:

image

Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM! This should be a great improvement for the dev-time experience. Thank you!

@elliott-with-the-longest-name-on-github
Copy link
Contributor

Anecdotally, I've seen a good number of people in the Discord that remove the div wrapper for "easier" styling, so... might be a good idea to try to find a way.

@tcc-sejohnson I in one project added to this div a style="display: contents;", and it was enough for me.

I don't know if that can cause a problem, but I haven't noticed any.

That won't work for everyone. To be clear, I don't think there's really any logical reason to remove the wrapper div -- it's easy enough to set it up however you want to -- but some people do it and we don't want to break their apps if possible 😁

@stephane-vanraes
Copy link
Contributor

stephane-vanraes commented Nov 10, 2022

That won't work for everyone. To be clear, I don't think there's really any logical reason to remove the wrapper div -- it's easy enough to set it up however you want to -- but some people do it and we don't want to break their apps if possible 😁

I am one of those removing the wrapper div, so maybe shedding some insights on that 🙂

The simple reason is that this div servers no purpose whatsoever in the final product*, and it makes styling harder to a degree (you always have to remember that the body of your page is not body for the css).

As far as I understand this div is a crutch for shortcoming of a tool used in development only and imho that is enough reason to try to find a way to make things work without, because utilities meant for development have no place in a production build.

This div might also clash in some instances where people used external stylesheet or css frameworks (for example an enterprise standard sheet)

*: besides potentially stopping hydration from removing extensions there injected markup, but this should not required adding extra elements to the markup.

@Rich-Harris
Copy link
Member Author

besides potentially stopping hydration from removing extensions there injected markup

this is the key — we've had multiple reports of exactly this sort of thing happening. it's very much not about preventing dev-time issues — it's the sort of bug that's likely to manifest in deeply confusing ways in production and that you'll be lucky to even find out about. we added a note to the docs...

image

...but i'm not sure that's enough, because people will always look at it and assume they can safely remove it. my personal inclination is to require %sveltekit.body% to be inside an element other than <body>, but i'm going to open a discussion to see how large a trade-off that would be

@Rich-Harris
Copy link
Member Author

#7585

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.

Support for tools like telefunc
6 participants