From a3485afc04e971e9ccdd26968c1905306b2b2e8b Mon Sep 17 00:00:00 2001 From: Bret Little Date: Mon, 28 Nov 2022 09:40:30 -0500 Subject: [PATCH] Fix --- package-lock.json | 33 ++++++- packages/hydrogen-remix/package.json | 22 +++++ packages/hydrogen-remix/src/build.ts | 1 + packages/hydrogen-remix/src/routing/routes.ts | 93 +++++++++++++++++++ .../templates/routes/__health.tsx | 3 + .../hydrogen-remix/templates/routes/admin.tsx | 6 ++ .../templates/routes/graphiql.tsx | 45 +++++++++ .../templates/routes/route-manifest.json.tsx | 45 +++++++++ templates/demo-store/package.json | 1 - templates/demo-store/remix.config.js | 90 +----------------- tsup.config.ts | 8 +- 11 files changed, 253 insertions(+), 94 deletions(-) create mode 100644 packages/hydrogen-remix/src/build.ts create mode 100644 packages/hydrogen-remix/src/routing/routes.ts create mode 100644 packages/hydrogen-remix/templates/routes/__health.tsx create mode 100644 packages/hydrogen-remix/templates/routes/admin.tsx create mode 100644 packages/hydrogen-remix/templates/routes/graphiql.tsx create mode 100644 packages/hydrogen-remix/templates/routes/route-manifest.json.tsx diff --git a/package-lock.json b/package-lock.json index bbadaec36b..647944e222 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4444,6 +4444,15 @@ "@types/react": "*" } }, + "node_modules/@types/recursive-readdir": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/responselike": { "version": "1.0.0", "license": "MIT", @@ -14829,7 +14838,6 @@ }, "node_modules/recursive-readdir": { "version": "2.2.3", - "dev": true, "license": "MIT", "dependencies": { "minimatch": "^3.0.5" @@ -18434,6 +18442,12 @@ "packages/hydrogen-remix": { "name": "@shopify/hydrogen-remix", "version": "0.0.1", + "dependencies": { + "recursive-readdir": "^2.2.3" + }, + "devDependencies": { + "@types/recursive-readdir": "^2.2.1" + }, "peerDependencies": { "@remix-run/oxygen": "*", "@remix-run/react": "*", @@ -18496,7 +18510,6 @@ "postcss-import": "^15.0.0", "postcss-preset-env": "^7.8.2", "prettier": "^2.7.1", - "recursive-readdir": "^2.2.3", "rimraf": "^3.0.2", "tailwindcss": "^3.1.8", "typescript": "^4.8.3" @@ -20695,7 +20708,10 @@ }, "@shopify/hydrogen-remix": { "version": "file:packages/hydrogen-remix", - "requires": {} + "requires": { + "@types/recursive-readdir": "^2.2.1", + "recursive-readdir": "^2.2.3" + } }, "@shopify/mini-oxygen": { "version": "1.0.0", @@ -21225,6 +21241,15 @@ "@types/react": "*" } }, + "@types/recursive-readdir": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/responselike": { "version": "1.0.0", "requires": { @@ -22817,7 +22842,6 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-use": "^17.4.0", - "recursive-readdir": "^2.2.3", "rimraf": "^3.0.2", "schema-dts": "^1.1.0", "tailwindcss": "^3.1.8", @@ -27397,7 +27421,6 @@ }, "recursive-readdir": { "version": "2.2.3", - "dev": true, "requires": { "minimatch": "^3.0.5" } diff --git a/packages/hydrogen-remix/package.json b/packages/hydrogen-remix/package.json index 0046f9c444..539eadcb0f 100644 --- a/packages/hydrogen-remix/package.json +++ b/packages/hydrogen-remix/package.json @@ -28,6 +28,22 @@ "default": "./dist/production/index.js" } }, + "./build": { + "types": "./dist/production/build.d.ts", + "module": { + "development": "./dist/development/build.js", + "default": "./dist/production/build.js" + }, + "require": "./dist/build.cjs", + "import": { + "development": "./dist/development/build.js", + "default": "./dist/production/build.js" + }, + "default": { + "development": "./dist/development/build.js", + "default": "./dist/production/build.js" + } + }, "./package.json": "./package.json" }, "files": [ @@ -37,5 +53,11 @@ "@remix-run/oxygen": "*", "@remix-run/react": "*", "@shopify/hydrogen": "*" + }, + "dependencies": { + "recursive-readdir": "^2.2.3" + }, + "devDependencies": { + "@types/recursive-readdir": "^2.2.1" } } diff --git a/packages/hydrogen-remix/src/build.ts b/packages/hydrogen-remix/src/build.ts new file mode 100644 index 0000000000..4dfd06817d --- /dev/null +++ b/packages/hydrogen-remix/src/build.ts @@ -0,0 +1 @@ +export {hydrogenRoutes} from './routing/routes'; diff --git a/packages/hydrogen-remix/src/routing/routes.ts b/packages/hydrogen-remix/src/routing/routes.ts new file mode 100644 index 0000000000..ad70a7cf16 --- /dev/null +++ b/packages/hydrogen-remix/src/routing/routes.ts @@ -0,0 +1,93 @@ +import fs from 'fs'; +import esbuild from 'esbuild'; +import readDir from 'recursive-readdir'; +import path from 'path'; + +export type HydrogenRouteOptions = { + prefixLocalizedRoutes?: boolean; +}; + +export async function hydrogenRoutes( + defineRoutes: any, + options: HydrogenRouteOptions = {}, +) { + if (options.prefixLocalizedRoutes) { + await buildLangRoutes(); + } + + const templatesPath = path.resolve(__dirname, '../../templates'); + + // fs.copyFileSync(templatesPath) + + // const templates = await readDir(templatesPath); + + // for (const template of templates) { + // console.log(template); + // } + + // @todo - extract into packaged helper function + // @todo - add logic for i18n + // const appRoutesPath = path.resolve( + // '../../templates/demo-store', + // 'app/routes', + // ); + // @todo - generalize from `path.cwd()` + // const appRouteFiles = await readDir(appRoutesPath); + const hydrogenRoutesPath = path.resolve(process.cwd(), '.hydrogen/routes'); + const hydrogenRouteFiles = await readDir(hydrogenRoutesPath); + return defineRoutes((route: any) => { + for (const hydrogenRoute of hydrogenRouteFiles) { + const hydrogenRoutePath = path.relative(process.cwd(), hydrogenRoute); + + const hydrogenRouteUrl = hydrogenRoutePath.substring( + hydrogenRoutePath.lastIndexOf('/'), + hydrogenRoutePath.lastIndexOf('.'), + ); + + route(hydrogenRouteUrl, '../' + hydrogenRoutePath); + } + }); +} + +async function buildLangRoutes() { + const appDir = path.resolve(process.cwd(), 'app'); + const routesDir = path.resolve(appDir, 'routes'); + const langDir = path.resolve(routesDir, '$lang'); + + const files = await readDir(routesDir, [ + (file) => { + return !!file.replace(/\\/g, '/').match(/routes\/\$lang\//); + }, + ]); + + // eslint-disable-next-line no-console + console.log(`Duplicating ${files.length} route(s) for translations`); + + for (let file of files) { + let bundle = await esbuild.build({ + entryPoints: {entry: file}, + bundle: false, + metafile: true, + write: false, + }); + + const moduleExports = bundle?.metafile?.outputs['entry.js'].exports; + + const moduleId = + '~/' + + path + .relative(appDir, file) + .replace(/\\/g, '/') + .slice(0, -path.extname(file).length); + + const outFile = path.resolve(langDir, path.relative(routesDir, file)); + + fs.mkdirSync(path.dirname(outFile), {recursive: true}); + fs.writeFileSync( + outFile, + `export {${moduleExports!.join(', ')}} from ${JSON.stringify( + moduleId, + )};\n`, + ); + } +} diff --git a/packages/hydrogen-remix/templates/routes/__health.tsx b/packages/hydrogen-remix/templates/routes/__health.tsx new file mode 100644 index 0000000000..af303fe239 --- /dev/null +++ b/packages/hydrogen-remix/templates/routes/__health.tsx @@ -0,0 +1,3 @@ +export async function loader() { + return new Response(null, {status: 200}); +} diff --git a/packages/hydrogen-remix/templates/routes/admin.tsx b/packages/hydrogen-remix/templates/routes/admin.tsx new file mode 100644 index 0000000000..7d6311b11b --- /dev/null +++ b/packages/hydrogen-remix/templates/routes/admin.tsx @@ -0,0 +1,6 @@ +import {LoaderArgs, redirect} from '@shopify/hydrogen-remix'; + +export async function loader({context}: LoaderArgs) { + const domain = context.storefront.getShopifyDomain(); + return redirect(domain + '/admin'); +} diff --git a/packages/hydrogen-remix/templates/routes/graphiql.tsx b/packages/hydrogen-remix/templates/routes/graphiql.tsx new file mode 100644 index 0000000000..a0480c0a50 --- /dev/null +++ b/packages/hydrogen-remix/templates/routes/graphiql.tsx @@ -0,0 +1,45 @@ +import {LoaderArgs} from '@shopify/hydrogen-remix'; + +export async function loader({context}: LoaderArgs) { + const url = context.storefront.getStorefrontApiUrl(); + const privateToken = + context.storefront.getPublicTokenHeaders()[ + 'X-Shopify-Storefront-Access-Token' + ]; + + return new Response( + ` + + + + + + Shopify Storefront API + + + + + +
+ + + + `, + {status: 200, headers: {'content-type': 'text/html'}}, + ); +} diff --git a/packages/hydrogen-remix/templates/routes/route-manifest.json.tsx b/packages/hydrogen-remix/templates/routes/route-manifest.json.tsx new file mode 100644 index 0000000000..48074ef17a --- /dev/null +++ b/packages/hydrogen-remix/templates/routes/route-manifest.json.tsx @@ -0,0 +1,45 @@ +import * as build from '@remix-run/dev/server-build'; +import {RESOURCE_TYPES, REQUIRED_RESOURCES} from '@shopify/hydrogen-remix'; + +type RESOURCE_TYPE = keyof typeof RESOURCE_TYPES; + +type LoaderOutput = { + customRoutes: Array<{pathname: string}>; + resourceRoutes: Array<{pathname: string; type: RESOURCE_TYPE}>; +}; + +export async function loader() { + const outputJSON: LoaderOutput = { + customRoutes: [], + resourceRoutes: [], + }; + + for (const [routeId, route] of Object.entries(build.routes)) { + const {resourceType} = route.module?.handle?.hydrogen ?? {}; + + if (!resourceType && route.path) { + outputJSON.customRoutes.push({ + pathname: route.path, + }); + continue; + } + + if (!RESOURCE_TYPES[resourceType as RESOURCE_TYPE]) { + console.warn( + `Unknown resource type on route ${route.id}: ${resourceType}`, + ); + continue; + } + + if (route.path) { + outputJSON.resourceRoutes.push({ + type: resourceType, + pathname: route.path, + }); + } + } + + // @todo warn if required resources are not defined! + + return outputJSON; +} diff --git a/templates/demo-store/package.json b/templates/demo-store/package.json index d8f6659de2..cba5d740ce 100644 --- a/templates/demo-store/package.json +++ b/templates/demo-store/package.json @@ -54,7 +54,6 @@ "postcss-import": "^15.0.0", "postcss-preset-env": "^7.8.2", "prettier": "^2.7.1", - "recursive-readdir": "^2.2.3", "rimraf": "^3.0.2", "tailwindcss": "^3.1.8", "typescript": "^4.8.3" diff --git a/templates/demo-store/remix.config.js b/templates/demo-store/remix.config.js index 9b81d8f903..7e8d163b79 100644 --- a/templates/demo-store/remix.config.js +++ b/templates/demo-store/remix.config.js @@ -1,94 +1,10 @@ -const path = require('path'); /** @type {import('@remix-run/dev').AppConfig} */ -const fs = require('fs'); -const esbuild = require('esbuild'); -const recursive = require('recursive-readdir'); +const {hydrogenRoutes} = require('@shopify/hydrogen-remix/build'); module.exports = { ignoredRouteFiles: ['**/.*'], - async routes() { - const appDir = path.resolve(__dirname, 'app'); - const routesDir = path.resolve(appDir, 'routes'); - const langDir = path.resolve(routesDir, '$lang'); - - const files = await recursive(routesDir, [ - (file) => { - return file.replace(/\\/g, '/').match(/routes\/\$lang\//); - }, - ]); - - // eslint-disable-next-line no-console - console.log(`Duplicating ${files.length} route(s) for translations`); - - for (let file of files) { - let bundle = await esbuild.build({ - entryPoints: {entry: file}, - bundle: false, - metafile: true, - write: false, - }); - - const moduleExports = bundle.metafile.outputs['entry.js'].exports; - - const moduleId = - '~/' + - path - .relative(appDir, file) - .replace(/\\/g, '/') - .slice(0, -path.extname(file).length); - - const outFile = path.resolve(langDir, path.relative(routesDir, file)); - - fs.mkdirSync(path.dirname(outFile), {recursive: true}); - fs.writeFileSync( - outFile, - `export {${moduleExports.join(', ')}} from ${JSON.stringify( - moduleId, - )};\n`, - ); - } - - return {}; - // Figure out why this won't work - // - // return defineRoutes((route) => { - // for (let file of files) { - // const relativeFilePath = file.replace(__dirname + "/app/routes/", ""); - // route("*/" + relativeFilePath, "routes/" + relativeFilePath); - - // console.log("/*/" + relativeFilePath, "routes/" + relativeFilePath); - // } - // }); + async routes(defineRoutes) { + return await hydrogenRoutes(defineRoutes, {prefixLocalizedRoutes: true}); }, }; - -// // @todo - extract into packaged helper function -// // @todo - add logic for i18n -// // const appRoutesPath = path.resolve( -// // '../../templates/demo-store', -// // 'app/routes', -// // ); -// // @todo - generalize from `path.cwd()` -// const hydrogenRoutesPath = path.resolve( -// '../../templates/demo-store', -// '.hydrogen/routes', -// ); -// // const appRouteFiles = await readDir(appRoutesPath); -// const hydrogenRouteFiles = await readDir(hydrogenRoutesPath); -// return defineRoutes((route) => { -// for (const hydrogenRoute of hydrogenRouteFiles) { -// const hydrogenRoutePath = path.relative( -// path.resolve('../../templates/demo-store'), -// hydrogenRoute, -// ); - -// const hydrogenRouteUrl = hydrogenRoutePath.substring( -// hydrogenRoutePath.lastIndexOf('/'), -// hydrogenRoutePath.lastIndexOf('.'), -// ); - -// route(hydrogenRouteUrl, '../' + hydrogenRoutePath); -// } -// }); -// }, diff --git a/tsup.config.ts b/tsup.config.ts index a32ec9571d..7d9aa000c1 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -6,10 +6,11 @@ const entry = 'src/index.ts'; const outDir = 'dist'; const common = defineConfig({ - entryPoints: [entry], + entryPoints: [entry, 'src/build.ts'], format: ['esm', 'cjs'], treeshake: true, sourcemap: true, + external: ['esbuild', 'fs', 'path', 'os'], }); export default defineConfig([ @@ -30,6 +31,11 @@ export default defineConfig([ `module.exports = process.env.NODE_ENV === 'development' ? require('./development/index.cjs') : require('./production/index.cjs');`, 'utf-8', ); + await fs.writeFile( + path.resolve(process.cwd(), outDir, 'build.cjs'), + `module.exports = process.env.NODE_ENV === 'development' ? require('./development/build.cjs') : require('./production/build.cjs');`, + 'utf-8', + ); }, }, ]);