Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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
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
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,7 +29,7 @@ export function FileRoutes({routes, basePath, dirPrefix}: FileRoutesProps) {

if (!routes) {
const fileRoutes = request.ctx.hydrogenConfig!.routes;
routes = fileRoutes?.files ?? (fileRoutes as ImportGlobEagerOutput);
routes = fileRoutes.files;
dirPrefix ??= fileRoutes?.dirPrefix as string;
basePath ??= fileRoutes?.basePath as string;
}
Expand Down Expand Up @@ -80,17 +79,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
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
import {Plugin, loadEnv, ResolvedConfig, normalizePath} from 'vite';
import {Plugin, loadEnv, ResolvedConfig} from 'vite';
import bodyParser from 'body-parser';
import path from 'path';
import {promises as fs} from 'fs';
import {hydrogenMiddleware, graphiqlMiddleware} from '../middleware';
import type {HydrogenVitePluginOptions} from '../../types';
import {InMemoryCache} from '../cache/in-memory';
import {VIRTUAL_PROXY_HYDROGEN_CONFIG_ID} from './vite-plugin-hydrogen-virtual-files';

export const HYDROGEN_DEFAULT_SERVER_ENTRY =
process.env.HYDROGEN_SERVER_ENTRY || '/src/App.server';

const virtualModuleId = 'virtual:hydrogen-config';
const virtualProxyModuleId = virtualModuleId + ':proxy';

export default (pluginOptions: HydrogenVitePluginOptions) => {
let config: ResolvedConfig;

return {
name: 'vite-plugin-hydrogen-middleware',
configResolved(_config) {
config = _config;
},
name: 'hydrogen:middleware',
/**
* By adding a middleware to the Vite dev server, we can handle SSR without needing
* a custom node script. It works by handling any requests for `text/html` documents,
Expand All @@ -42,7 +35,7 @@ export default (pluginOptions: HydrogenVitePluginOptions) => {
dev: true,
getShopifyConfig: async (incomingMessage) => {
const {default: hydrogenConfig} = await server.ssrLoadModule(
'virtual:hydrogen-config:proxy'
VIRTUAL_PROXY_HYDROGEN_CONFIG_ID
);

// @ts-ignore
Expand All @@ -59,9 +52,8 @@ export default (pluginOptions: HydrogenVitePluginOptions) => {
// via `ServerComponentRequest` during production runtime.
request.normalizedUrl = request.url;

return typeof hydrogenConfig.shopify === 'function'
? hydrogenConfig.shopify(request)
: hydrogenConfig.shopify;
const {shopify} = hydrogenConfig;
return typeof shopify === 'function' ? shopify(request) : shopify;
},
})
);
Expand All @@ -82,31 +74,6 @@ export default (pluginOptions: HydrogenVitePluginOptions) => {
})
);
},
async resolveId(source, importer) {
if (source === virtualModuleId) {
const configPath = await findHydrogenConfigPath(
config.root,
pluginOptions.configPath
);

return this.resolve(configPath, importer, {
skipSelf: true,
});
}

if (source === virtualProxyModuleId) {
// Virtual modules convention
// https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention
return '\0' + virtualProxyModuleId;
}
},
async load(id) {
if (id === '\0' + virtualProxyModuleId) {
// Likely due to a bug in Vite, but the config cannot be loaded
// directly using ssrLoadModule. It needs to be proxied as follows:
return `import hc from 'virtual:hydrogen-config'; export default hc;`;
}
},
} as Plugin;
};

Expand All @@ -130,27 +97,3 @@ async function polyfillOxygenEnv(config: ResolvedConfig) {

globalThis.Oxygen = {env};
}

async function findHydrogenConfigPath(root: string, userProvidedPath?: string) {
let configPath = userProvidedPath;

if (!configPath) {
// Find the config file in the project root
const files = await fs.readdir(root);
configPath = files.find((file) => /^hydrogen\.config\.[jt]s$/.test(file));
}

if (configPath) {
configPath = normalizePath(configPath);

if (!configPath.startsWith('/'))
configPath = path.resolve(root, configPath);
}

return (
configPath ||
require.resolve(
'@shopify/hydrogen/dist/esnext/utilities/empty-hydrogen-config.js'
)
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// @ts-ignore
import reactServerDomVite from '@shopify/hydrogen/vendor/react-server-dom-vite/plugin';
import {HYDROGEN_DEFAULT_SERVER_ENTRY} from './vite-plugin-hydrogen-middleware';
import {createServer} from 'vite';
import {VIRTUAL_PROXY_HYDROGEN_ROUTES_ID} from './vite-plugin-hydrogen-virtual-files';
import {viteception} from '../viteception';

export default function () {
return reactServerDomVite({
Expand All @@ -17,22 +18,14 @@ export default function () {
);
},
async findClientComponentsForClientBuild() {
// In client build, we create a local server to discover client compoents.
const server = await createServer({
clearScreen: false,
server: {middlewareMode: 'ssr'},
});

await Promise.all([
const {server} = await viteception([
// Load server entry to discover client components early
server.ssrLoadModule(HYDROGEN_DEFAULT_SERVER_ENTRY),
// Route globs are placed in hydrogen.config.js and need to
HYDROGEN_DEFAULT_SERVER_ENTRY,
// Route globs are placed in a virtual module and need to
// be loaded to discover client components in routes
server.ssrLoadModule('virtual:hydrogen-config:proxy'),
VIRTUAL_PROXY_HYDROGEN_ROUTES_ID,
]);

await server.close();

// At this point, the server has loaded all the components in the module graph
return reactServerDomVite.findClientComponentsFromServer(server);
},
Expand Down
Loading