Fixes WEB-501
Fixes https://github.com/vercel/turbo/issues/3139
This adds proper support for the [`variable`
property](https://nextjs.org/docs/api-reference/next/font#variable) when
constructing fonts. This results in:
* defining a selector in the css module for a classname defining the css
custom property (css variable), whose value is the font family
* adding a `variable` property to the resulting js object whose value is
the classname used in the selector above
Test Plan: Added an integration test.
This implements routing by using a-yet-to-be-implemented API exposed by
Next.js. The API follows something similar to:
```typescript
type MakeResolver = (config: NextConfig) => Resolver;
type Resolver = (IncomingMessage, ServerResponse) => Promise<void> | void;
import { makeResolver } from "next/dist/...";
const resolver = makeResolver(nextConfig as object);
// Later, once we have a request we'd like to route:
// We don't care what the promise resolved to, we just want it to settle.
await resolver(req, res);
```
The resolver can do 1 of 3 things with this:
1. ~~Return a redirect response~~ Removed
2. Return a rewrite response
3. Stream a middleware response
> ~~1. Return a redirect response~~
<details>
First, ensure a `x-nextjs-route-result: 1` header is present on the
response. Then return a JSON encoded body:
```typescript
{
url: string,
statusCode: u16,
headers: Record<string, string>
isRedirect: true
}
```
The Rust server will then respond with a redirect using to the
appropriate location.
</details>
> 2. Return a rewrite response
First, ensure a `x-nextjs-route-result: 1` header is present on the
response. Then return a JSON encoded body:
```typescript
{
url: string,
headers: Record<string, string>
}
```
The Rust server will use this updated URL to request content from our
handlers.
> 3. Stream a middleware response
Ensure `x-nextjs-route-result` header **is not present** on the
response. All headers will be sent back, and the body will be streamed
back to the browser.
- - -
TODO:
- ~~Do `headers` actually matter to a `redirect`~~ Yes?
- ~~Does `statusCode` actually matter to a `rewrite`?~~ No
- ~~We can't handle streaming body responses yet.~~ Mocked by buffering.
Fixes WEB-228
Co-authored-by: JJ Kasper <jj@jjsweb.site>
This adds support for metadata in pages and layouts.
Full metadata support also needs support for implicit metadata with
files named `icon.ico` etc.
This PR also improves the test suite and adds a basic test case for app
dir support
In addition to the fix, I've extracted the path regex/params matching logic from `turbopack-node` to `next-core`. `turbopack-node` now only declares a value trait which `next-core` implements.
fixes WEB-141
This changes the ContentSource API.
Before a ContentSource returned a tuple of specificity and content.
Now it returns a tuple of specificity and a get_content function.
The old way made it very inefficient to combine multiple ContentSource.
All combined ContentSources were ask before, all returned specificity
and content, and they are ordered after that. That required to compute
all contents, even if it is not really used after ordering.
Now we order specificity and a get_content function and only compute the
content (by calling get_content) with the final result.
It also changes how data needs are expressed in the `get_content`
function. Instead of asking it over and over again with more data, it
statically returns the needed data with `vary` and the `get` function is
only called with that data. This is technically more limited than the
old way, but one can workaround that if needed. But practically we
probably never need that. On the other hand it improves the number of
function calls, since the `vary` method is only called once and the
`get` only once per request. Before data needs required at least 2 `get`
calls per request.
Our `pageData` HMR process treated an undefined response as an error condition, but if the page doesn't have a `getXyzProps` exported method, then this is the default response. This prevented us from having any pages without page props.
The new code just sends down an empty object, which seems to work for establishing the connection. HMR updates are sent down (and seem to trigger restarts, at least from what I tested with `getStaticProps`).
Fixes WEB-445
This updates our `mdxjs` dependency to the tip of
https://github.com/wooorm/mdxjs-rs/pull/11, so that we can update it's
`swc_core` dependency (it conflicts with ours).
It also updates the `testing` crate to update it's `swc_common`
dependency (also conflicting with ours), and makes it a workspace
dependency.
Fixes WEB-412.
Previously, references to styled-jsx inserted by the swc transform would be bundled, which duplicated the copy required by next, which is external. This marks the dependency is to be resolved as external always.
Test Plan: Verified in a small app that `<style jsx>` nodes result in a server-rendered response with the appropriate `<style>` tag in the head.
This implements a debug mode for spawning Node processes across multiple surfaces including `evaluate` and `get_renderer_pool`.
It:
* automatically limits concurrency to 1 process per pool
* passes `--inspect-brk` to spawned Node process
* sets the timeout to effectively-infinite duration
Test Plan: set the value to true for the call to `get_renderer_pool` in render_static.rs and attached to a debuggable server renderer process.
This:
* Implements a basic http server to mock returning a stylesheet from the Google Fonts API (**Note**: This importantly does *not* mock returning the font resources themselves, which are currently loaded by the browser. We should implement something to do this when we implement caching arbitrary http resources traced from `url()` and this is no longer loaded by the test browser)
* Adds an integration test that asserts the basic shape of the JS object returned by font functions
* ~Adds an integration test that asserts the browser correctly loads a font for the ascii unicode range, along with the appropriate `font-display`, variant, etc.~ Unfortunately `document.fonts` is not reliable with different font-display loading patterns as any of them can fall back.
As noted, this does not mock responses from Google for the font resources themselves, which are currently loaded by the test browser. This means that we'll be dependent on this external service for passing integration tests until we implement caching of `url()`s in Turbopack. We should monitor the reliability of this test.
https://github.com/vercel/next.js/pull/44668 refactored Next's use of `AsyncLocalStorage`, and installs a "polyfill" of the API by patching the node import onto `globalThis.` Importantly, it's then used in the module scope during imports, so we need to install the polyfill early in the app rendering startup.
Fixes https://github.com/vercel/turbo/issues/3319
This adds two basic tests for next/dynamic:
* one ensures that SSR supports dynamic components;
* the other ensures that SSR doesn't run when `ssr: false`.
This PR adds the next/dynamic SWC transform to the repo. This is copied
over from the implementation in
[](f70a6bfb86/packages/next-swc/crates/core/src/next_dynamic.rs),
with an additional mode for Turbopack.
For now, it applies it to all sources files (excluding node_modules, but
including embedded modules).
I've refactored the Next transforms logic to make it more easily
extendable in the future, and avoid creating more Vcs than absolutely
necessary.
This PR is the last item in the list of what's needed to support
next/dynamic in development.
The `processed_assets` `IndexSet` was performing deduplication on the `AssetVc`, which is the same between static (`import ... from "foo"`) and dynamic (`import("foo")`) imports of the same specifier. But, the _reference_ to those assets is different, and generates different chunking semantics. In order for both to succeed, we need to process both assets.
Coupled with vercel/turbo#3193's ability to load chunks on the server side, this fixes fixes WEB-381.
add the minimum to run a simple raw-loader (see test case)
* add `experimental.turbopackWebpackLoaders` to next.config.js
* key is extension like `".mdx"`, value is an array of loaders like
`["mdx-loader"]`
This PR separates Turbopack's `runtime.js` into two:
- the Browser/DOM implementation, which uses `<script>` and `<link>`
tags for dynamically loading chunks;
- the Node.js/CommonJS implementation, which uses `require` instead.
~~The two runtimes share a lot of code, but I'm not sure what's the best
approach for sharing this logic, or even if we should, so for now they
are two separate entities.~~
The shared code between the two runtimes is now in a separate file to
avoid duplication.
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Addresses an issue currently affecting non-variable fonts in which
`next-dev` errors for non-variable Google fonts. This issue can be
replicated by using `next dev --turbo` and using a Google font that
isn't variable, like Hind.
The problem is resolved by unwrapping axes only if the font is variable.
Relevant issue: vercel/next.js#44282
Co-authored-by: Will Binns-Smith <wbinnssmith@gmail.com>
This is a straightforward chore PR to move next_client and next_server modules
around, in order to make navigation and imports more predictable between them.
I'm also planning to introduce a next_shared::context in a further PR, hence the
changes.
Based on vercel/turbo#2968
This builds upon vercel/turbo#2968 and @ForsakenHarmony's work on data routes to
enable page data HMR.
Page data HMR is a bit more clever than it is in Next.js as we won't
re-render a Node.js result for each page file update. Instead, thanks to
the `StripPageDefaultExport` transform, there are three versions of the
page chunks:
* client-side (strips page data exports);
* server-side (full);
* data server-side (strips page default export).
Instead of subscribing to the full server-side result, on hydration, the
client-side page separately subscribes to:
* client-side updates (already the case);
* data server-side updates (new).
This means that updating something that only affects the page component
will only cause a client-side update and **no Node.js re-rendering**,
while updating something that only affects the data will only cause a
server-side update.
~~I'm marking this as a draft for now as there are still a few areas to
test/investigate:~~
- [x] When something that is used in both the default page export and
data exports is changed, this will cause *two* HMR updates: one data
update, and one client-side chunk update. **The same case breaks in
Next.js, where we will receive a client-side update, but no server-side
update, ending up with an incorrect result.**
- [x] Differences between `getStaticProps/getServerSideProps`, as well
as `getInitialProps` (need to talk with @timneutkens about this) (see
https://github.com/vercel/next.js/pull/44523)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
## The original transform
The original behavior of the Next SSG transform is to remove `getServerSideProps`, `getStaticProps`, and `getStaticPaths` from Next.js page files so they can be bundled for the client. This is what enables the following code to work properly without advanced tree shaking:
```jsx
import db from "db";
import PostCounter from
export default function Home(props) {
return <>{props.posts.length} post(s)</>;
}
const postsPromise = db.getPosts();
export async function getStaticProps() {
return {
props: {
posts: await postsPromise,
},
};
}
```
The transform is able to remove both `getStaticProps` and all its exclusive, transitive dependencies, so this is what the client would see:
```jsx
import PostCounter from "components/PostCounter";
export var __N_SSG = true;
export default function Home(props) {
return __jsx(PostCounter, {
count: props.posts.length
});
}
```
## Adding the inverse operation
However, to support proper HMR for these data exports, we need to be able to execute somewhat of an inverse operation: remove the default component export, but preserve all the rest. This allows Turbopack to bundle server-side only declarations, only re-rendering when one of these changes, instead of re-rendering on any server-side and client-side change.
From our module above, the updated transform is now also able to generate the following:
```jsx
import db from "db";
const postsPromise = db.getPosts();
export async function getStaticProps() {
return {
props: {
posts: await postsPromise
}
};
}
```
As you can see, this module is no longer importing the `PostCounter`, which means re-rendering will not invalidate when that counter changes. However, if the "db" module changes, we will still be able to detect a change and re-render.
## Other notes
* I renamed the transform from "next_ssg" to "next_transform_strip_page_exports". It's much more verbose, but hopefully also much clearer about what it does at a glance.
* I took the liberty to clean up and comment some parts of the transform to make it more easily understandable (at least for someone like me, who hasn't written a lot of SWC code). I also fixed a few bugs and edge cases.
* I brought over the tests from the transform in the Next.js and added a couple of them.
* For now, only the `StripDataExports` filter is used. A future PR will build on this and @ForsakenHarmony's https://github.com/vercel/turbo/pull/2949 PR to actually implement SSR/SSG HMR.
## Reviewing guide
1. The crux of the change is the move (and refactor) of the next ssg transform from https://github.com/vercel/turbo/pull/2968/files#diff-133d73657647ed793ca4782a73552650b32ad565094b1e0faf452ad58705499b to https://github.com/vercel/turbo/pull/2968/files#diff-d6442fa6af9b66e581f062739dd6de2419f5e8f6f3d97cfa63518c72b0a9ee3e.
2. I also added the [errors.rs](https://github.com/vercel/turbo/pull/2968/files#diff-0f308375da4179c0ea5a0fcbd99593b56d6020cd7dec1694ed08f392f1637c09) and [fixture.rs](https://github.com/vercel/turbo/pull/2968/files#diff-6e23f34483fc17a27dfc630edb455ea95e28d5cb350468c2ba01384fbc3c116a) tests. I adapted fixture.rs to execute on the two transform filters: data exports and default export.
3. Most of the tests in `tests/` are copied from https://github.com/vercel/next.js/tree/canary/packages/next-swc/crates/core/tests. The changes I made are:
i. https://github.com/vercel/turbo/pull/2968/files#diff-774abee6a1bf139c9ce55e226bf15b52e56ea091170ee5d6295c191fd8d793c7: made this one symmetric for both strip data and strip default transforms.
ii. https://github.com/vercel/turbo/pull/2968/files#diff-4792266a264dc67da93748d2c6522917f860527a689891bd5f8f4add9841e7f6 wasn't supported before AFAIK.
iii. https://github.com/vercel/turbo/pull/2968/files#diff-a3b12adbce1dec40f39ff8af13ffecbe7f6963e21bc402cef6332ecf5018877e similar to i.
Currently when an individual `ContentSource` inside a `CombinedContentSource` requests additional vary data, the combined source will treat that source as the winner of the query. But, sometimes the vary data is necessary to determine that the content is not found by this source. And if that's the case, we'll hit a 404 when we should actually keep iterating.
This is exactly the case we're going to hit with redirect/rewrites. Redirects need to be the very first content source, and I also need query/header/cookie/hostname data in order to determine if a redirect applies. Without this, **every** request becomes a 404.
- The 10th attempt used to day "trying again" and then didn't try again because the iterator ended…
- Swaps a nested `.map() == Some(bool)` for a `and_then`
- Extracts into a helper function so code can early return without an `Option<Result>` wrapper.
- Adds `details` to `SourceMapContentSource`
- Fixes `ty` of `SourceMapContentSource`
- Adds default `children` trait method that returns empty children