Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
beb0624
Drop import.meta.globEager in dev
frandiox May 19, 2022
886360a
Refactor variables and virtual modules
frandiox May 20, 2022
af3b972
Fix code after cherry-pick
frandiox May 20, 2022
f3c3bca
Extract Vitception
frandiox May 20, 2022
441e604
Use Vitception to load routes during build
frandiox May 20, 2022
5f0bc0e
Use static imports to fix build
frandiox May 20, 2022
f48ca85
Add default routes path
frandiox May 20, 2022
bf409b4
Fix types and paths
frandiox May 24, 2022
9558d46
Fix dirPrefix issues
frandiox May 24, 2022
9729ef5
Merge branch 'v1.x-2022-07' into fd-drop-import-globs
frandiox May 24, 2022
43384a4
Fix HMR in route files
frandiox May 24, 2022
24a9c15
Use default value for config.routes
frandiox May 24, 2022
112f334
Fix issue in Node 16.15
frandiox May 27, 2022
24710b1
Extract virtual-files plugin for clarity
frandiox May 27, 2022
34699e4
Merge branch 'v1.x-2022-07' into fd-drop-import-globs
frandiox May 27, 2022
259db55
Cleanup
frandiox May 27, 2022
20119a1
Fix unit tests
frandiox May 27, 2022
1c95e85
Merge branch 'v1.x-2022-07' into fd-drop-import-globs
frandiox May 30, 2022
5a23ae8
Update docs
frandiox May 30, 2022
24a4943
Changeset
frandiox May 30, 2022
79d95fd
Cleanup
frandiox May 30, 2022
83b9138
Regenerate broken graphql.schema.json
frandiox May 30, 2022
e0ffbf6
Disable rules-of-hooks in server components
frandiox May 30, 2022
d130f1c
Disable prefer-gql in test
frandiox May 30, 2022
720d786
Apply suggestions from code review
frandiox May 31, 2022
a14c2b5
Merge branch 'v1.x-2022-07' into fd-drop-import-globs
frandiox May 31, 2022
e9b51a5
Revert "Disable prefer-gql in test"
frandiox May 31, 2022
689c3df
Revert "Disable rules-of-hooks in server components"
frandiox May 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .changeset/ninety-garlics-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
'@shopify/hydrogen': minor
'create-hydrogen-app': minor
---

The `routes` property in `hydrogen.config.js` file has been simplified. It is now a string that represents the path to the routes from the project root:

```diff
// hydrogen.config.js

export default defineConfig({
- routes: import('./src/routes/**/*.server.[jt](s|sx)'),
+ routes: '/src/routes',
});
```

Its default value is `/src/routes` so this property can be removed when using this directory.

In the object syntax version, `dirPrefix` is removed and `files` becomes a string:

```diff
// hydrogen.config.js

export default defineConfig({
routes: {
- files: import('./src/routes/**/*.server.[jt](s|sx)'),
- dirPrefix: './src/routes',
+ files: '/src/routes',
basePath: '/',
},
});
```
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,11 @@ module.exports = {
'node/no-missing-import': 'off',
},
},
{
files: ['**/*.server.*'],
rules: {
'react-hooks/rules-of-hooks': 'off',
},
},
],
};
11 changes: 9 additions & 2 deletions docs/components/framework/fileroutes.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
---
gid: 182b039d-d09d-4513-8759-b51412cc8293
title: FileRoutes
description: The FileRoutes component builds a set of default Hydrogen routes based on the output provided by Vite's import.meta.globEager method.
description: The `FileRoutes` component builds a set of Hydrogen routes.
---

The `FileRoutes` component builds a set of default Hydrogen routes based on the output provided by Vite's [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. You can have multiple instances of this component to source file routes from multiple locations.
The `FileRoutes` component builds a set of Hydrogen routes. By default, it loads the routes specified in [the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config) when no props are passed.

It is also possible to override the default behavior and use custom routes based on the output provided by Vite's [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. You can have multiple instances of this component to source file routes from multiple locations.

## Example code

{% codeblock file, filename: 'App.server.jsx' %}

```jsx
import {Router, FileRoutes, Route} from '@shopify/hydrogen';

function App() {
const esRoutes = import.meta.globEager('./custom-routes/es/**/*.server.jsx');
const enRoutes = import.meta.globEager('./custom-routes/en/**/*.server.jsx');

return (
<Suspense fallback={<LoadingFallback />}>
<ShopifyProvider>
<CartProvider>
<Router>
<FileRoutes />
<FileRoutes basePath="/es/" routes={esRoutes} />
<FileRoutes basePath="/en/" routes={enRoutes} />
<Route path="*" page={<NotFound />} />
Expand Down
22 changes: 7 additions & 15 deletions docs/framework/hydrogen-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ The Hydrogen configuration file contains information that's needed at runtime fo
```tsx
import {defineConfig} from '@shopify/hydrogen/config';

/* All properties in this configuration file are required. */

/* The `defineConfig` function is an optional utility that provides types for the configuration object. */
export default defineConfig({
/* The routes defined by Vite's import.meta.globEager method. */
routes: import.meta.globEager('./src/routes/**/*.server.[jt](s|sx)'),
routes: '/src/routes',
/* The information that your app needs to connect to the Storefront API. */
shopify: {
/* The domain of your Shopify store */
Expand All @@ -49,15 +47,14 @@ The following groupings of configuration properties can exist in Hydrogen:

### `routes`

The `routes` property is where you can provide server components and API handlers using Vite's [`import.meta.globEager`](https://vitejs.dev/guide/features.html#glob-import) method.

By default, Hydrogen detects the common prefix of every route and removes it from the URLs. In the following example, `./src/routes` would be detected as the common prefix:
The `routes` property is where you can provide a path to find server components and API handlers. Its default value is `/src/routes` but it can be customized to any directory specified **from the project root**:

{% codeblock file, filename: 'hydrogen.config.js' %}

```tsx
export default defineConfig({
routes: import.meta.globEager('./src/routes/**/*.server.[jt](s|sx)'),
/* Path from the project root to the files for server components and API handlers */
routes: '/path/to/routes',
});
```

Expand All @@ -70,14 +67,9 @@ If your app requires a more advanced configuration, then you can provide additio
```tsx
export default defineConfig({
routes: {
/* The file routes for server components and API handlers */
files: import.meta.globEager('./src/routes/**/*.server.[jt](s|sx)'),
/* (Optional) The portion of the file route path that shouldn't be a part of the URL.
* You need to modify this if you want to import your routes from a location other
than the default `src/routes`.
*/
dirPrefix: './src/routes',
/* (Optional) A path that's prepended to all file routes. You can modify `basePath`
/* Path from the project root to the files for server components and API handlers */
files: '/path/to/routes',
/* A path that's prepended to all file routes. You can modify `basePath`
* if you want to prefix all file routes. For example, you can prefix all file routes with a locale.
*/
basePath: '/',
Expand Down
1 change: 0 additions & 1 deletion examples/css-modules/hydrogen.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {defineConfig} from '@shopify/hydrogen/config';

export default defineConfig({
routes: import.meta.globEager('./src/routes/**/*.server.[jt](s|sx)'),
shopify: {
storeDomain: 'hydrogen-preview.myshopify.com',
storefrontToken: '3b580e70970c4528da70c98e097c2fa0',
Expand Down
1 change: 0 additions & 1 deletion examples/rust/hydrogen.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {defineConfig} from '@shopify/hydrogen/config';

export default defineConfig({
routes: import.meta.globEager('./src/routes/**/*.server.[jt](s|sx)'),
shopify: {
storeDomain: 'hydrogen-preview.myshopify.com',
storefrontToken: '3b580e70970c4528da70c98e097c2fa0',
Expand Down
1 change: 0 additions & 1 deletion examples/typescript/hydrogen.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {defineConfig} from '@shopify/hydrogen/config';

export default defineConfig({
routes: import.meta.globEager('./src/routes/**/*.server.[jt](s|sx)'),
shopify: {
storeDomain: 'hydrogen-preview.myshopify.com',
storefrontToken: '3b580e70970c4528da70c98e097c2fa0',
Expand Down
2 changes: 1 addition & 1 deletion packages/hydrogen/graphql.schema.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions packages/hydrogen/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {HydrogenConfig} from './types';
import type {InlineHydrogenConfig} from './types';

export const defineConfig = (params: HydrogenConfig) => params;
export const defineConfig = (params: InlineHydrogenConfig) => params;

export type {HydrogenConfig};
export type {InlineHydrogenConfig as HydrogenConfig};
29 changes: 20 additions & 9 deletions packages/hydrogen/src/entry-server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import type {
RendererOptions,
StreamerOptions,
HydratorOptions,
HydrogenConfig,
ImportGlobEagerOutput,
ResolvedHydrogenConfig,
ResolvedHydrogenRoutes,
} from './types';
import {Html, applyHtmlHead} from './framework/Hydration/Html';
import {ServerComponentResponse} from './framework/Hydration/ServerComponentResponse.server';
Expand Down Expand Up @@ -79,7 +80,7 @@ export interface RequestHandler {
>;
}

export const renderHydrogen = (App: any, hydrogenConfig?: HydrogenConfig) => {
export const renderHydrogen = (App: any) => {
const handleRequest: RequestHandler = async function (rawRequest, options) {
const {
indexTemplate,
Expand All @@ -94,12 +95,22 @@ export const renderHydrogen = (App: any, hydrogenConfig?: HydrogenConfig) => {
const request = new ServerComponentRequest(rawRequest);
const url = new URL(request.url);

if (!hydrogenConfig) {
const {default: inlineHydrogenConfig} = await import(
// @ts-ignore
// eslint-disable-next-line node/no-missing-import
const configFile = await import('virtual:hydrogen-config');
hydrogenConfig = configFile.default as HydrogenConfig;
}
'virtual__hydrogen.config.ts'
);

const {default: hydrogenRoutes} = await import(
// @ts-ignore
// eslint-disable-next-line node/no-missing-import
'virtual__hydrogen-routes.server.jsx'
);

const hydrogenConfig: ResolvedHydrogenConfig = {
...inlineHydrogenConfig,
routes: hydrogenRoutes,
};

request.ctx.hydrogenConfig = hydrogenConfig;
request.ctx.buyerIpHeader = buyerIpHeader;
Expand Down Expand Up @@ -136,7 +147,7 @@ export const renderHydrogen = (App: any, hydrogenConfig?: HydrogenConfig) => {

const isReactHydrationRequest = url.pathname === RSC_PATHNAME;

if (!isReactHydrationRequest && hydrogenConfig.routes) {
if (!isReactHydrationRequest) {
const apiRoute = getApiRoute(url, hydrogenConfig.routes);

// The API Route might have a default export, making it also a server component
Expand Down Expand Up @@ -211,8 +222,8 @@ export const renderHydrogen = (App: any, hydrogenConfig?: HydrogenConfig) => {
)) as RequestHandler;
};

function getApiRoute(url: URL, routes: NonNullable<HydrogenConfig['routes']>) {
const apiRoutes = getApiRoutes(routes!);
function getApiRoute(url: URL, routes: ResolvedHydrogenRoutes) {
const apiRoutes = getApiRoutes(routes);
return getApiRouteFromURL(url, apiRoutes);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {useServerRequest} from '../ServerRequestProvider';

import type {ImportGlobEagerOutput} from '../../types';
import {RouteParamsProvider} from '../useRouteParams/RouteParamsProvider.client';
import {findRoutePrefix} from '../../utilities/findRoutePrefix';

interface FileRoutesProps {
/** The routes defined by Vite's [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. */
Expand All @@ -30,9 +29,9 @@ export function FileRoutes({routes, basePath, dirPrefix}: FileRoutesProps) {

if (!routes) {
const fileRoutes = request.ctx.hydrogenConfig!.routes;
routes = fileRoutes?.files ?? (fileRoutes as ImportGlobEagerOutput);
dirPrefix ??= fileRoutes?.dirPrefix as string;
basePath ??= fileRoutes?.basePath as string;
routes = fileRoutes.files;
dirPrefix ??= fileRoutes.dirPrefix;
basePath ??= fileRoutes.basePath;
}

basePath ??= '/';
Expand Down Expand Up @@ -78,17 +77,15 @@ interface HydrogenRoute {
export function createPageRoutes(
pages: ImportGlobEagerOutput,
topLevelPath = '*',
dirPrefix?: string | RegExp
dirPrefix: string | RegExp = ''
): HydrogenRoute[] {
const topLevelPrefix = topLevelPath.replace('*', '').replace(/\/$/, '');

const keys = Object.keys(pages);

const commonRoutePrefix = dirPrefix ?? findRoutePrefix(keys);

const routes = keys
.map((key) => {
const path = extractPathFromRoutesKey(key, commonRoutePrefix);
const path = extractPathFromRoutesKey(key, dirPrefix);

/**
* Catch-all routes [...handle].jsx don't need an exact match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import type {ShopifyContextValue} from '../../foundation/ShopifyProvider/types';
import {getTime} from '../../utilities/timing';
import type {QueryCacheControlHeaders} from '../../utilities/log/log-cache-header';
import type {QueryTiming} from '../../utilities/log/log-query-timeline';
import type {HydrogenConfig, PreloadOptions, QueryKey} from '../../types';
import type {
ResolvedHydrogenConfig,
PreloadOptions,
QueryKey,
} from '../../types';
import {hashKey} from '../../utilities/hash';
import {HelmetData as HeadData} from 'react-helmet-async';
import {RSC_PATHNAME} from '../../constants';
Expand Down Expand Up @@ -51,7 +55,7 @@ export class ServerComponentRequest extends Request {
public ctx: {
cache: Map<string, any>;
head: HeadData;
hydrogenConfig?: HydrogenConfig;
hydrogenConfig?: ResolvedHydrogenConfig;
shopifyConfig?: ShopifyContextValue;
queryCacheControl: Array<QueryCacheControlHeaders>;
queryTimings: Array<QueryTiming>;
Expand Down
2 changes: 2 additions & 0 deletions packages/hydrogen/src/framework/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import hydrogenConfig from './plugins/vite-plugin-hydrogen-config';
import type {Plugin} from 'vite';
import hydrogenMiddleware from './plugins/vite-plugin-hydrogen-middleware';
import hydrogenClientMiddleware from './plugins/vite-plugin-hydrogen-client-middleware';
import hydrogenVirtualFiles from './plugins/vite-plugin-hydrogen-virtual-files';
import platformEntry from './plugins/vite-plugin-platform-entry';
import rsc from './plugins/vite-plugin-hydrogen-rsc';
import ssrInterop from './plugins/vite-plugin-ssr-interop';
Expand All @@ -20,6 +21,7 @@ export default (pluginOptions: HydrogenVitePluginOptions = {}) => {
hydrogenClientMiddleware(),
clientImports(),
hydrogenMiddleware(pluginOptions),
hydrogenVirtualFiles(pluginOptions),
react(),
hydrationAutoImport(),
ssrInterop(),
Expand Down
Loading