@shopify/cli-hydrogen 7.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/hydrogen/build.js +3 -8
- package/dist/commands/hydrogen/deploy.js +79 -32
- package/dist/commands/hydrogen/deploy.test.js +162 -5
- package/dist/commands/hydrogen/generate/route.js +6 -1
- package/dist/commands/hydrogen/init.test.js +2 -1
- package/dist/commands/hydrogen/setup.js +17 -19
- package/dist/generator-templates/starter/CHANGELOG.md +45 -0
- package/dist/generator-templates/starter/README.md +25 -2
- package/dist/generator-templates/starter/app/components/Cart.tsx +2 -2
- package/dist/generator-templates/starter/app/components/Layout.tsx +9 -1
- package/dist/generator-templates/starter/app/components/Search.tsx +44 -15
- package/dist/generator-templates/starter/app/lib/search.ts +29 -0
- package/dist/generator-templates/starter/app/root.tsx +0 -2
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +2 -2
- package/dist/generator-templates/starter/app/routes/api.predictive-search.tsx +1 -21
- package/dist/generator-templates/starter/app/routes/cart.tsx +1 -5
- package/dist/generator-templates/starter/app/routes/search.tsx +8 -2
- package/dist/generator-templates/starter/app/styles/app.css +10 -15
- package/dist/generator-templates/starter/package.json +7 -7
- package/dist/generator-templates/starter/remix.config.js +1 -0
- package/dist/generator-templates/starter/remix.env.d.ts +6 -2
- package/dist/generator-templates/starter/server.ts +1 -0
- package/dist/hooks/init.js +3 -3
- package/dist/lib/codegen.js +1 -8
- package/dist/lib/file.js +4 -1
- package/dist/lib/flags.js +6 -0
- package/dist/lib/graphiql-url.js +3 -0
- package/dist/lib/mini-oxygen/assets.js +17 -1
- package/dist/lib/onboarding/common.js +4 -3
- package/dist/lib/onboarding/local.js +7 -7
- package/dist/lib/onboarding/remote.js +2 -1
- package/dist/lib/setups/i18n/replacers.test.js +3 -2
- package/dist/lib/setups/routes/generate.js +58 -10
- package/dist/lib/setups/routes/templates/locale-check.js +9 -0
- package/dist/lib/setups/routes/templates/locale-check.ts +16 -0
- package/dist/lib/shell.js +1 -1
- package/dist/lib/template-diff.js +13 -3
- package/dist/virtual-routes/components/RequestDetails.jsx +2 -2
- package/oclif.manifest.json +47 -8
- package/package.json +5 -5
|
@@ -50,7 +50,7 @@ describe("i18n replacers", () => {
|
|
|
50
50
|
|
|
51
51
|
import type {
|
|
52
52
|
Storefront,
|
|
53
|
-
|
|
53
|
+
CustomerAccount,
|
|
54
54
|
HydrogenCart,
|
|
55
55
|
} from "@shopify/hydrogen";
|
|
56
56
|
import type {
|
|
@@ -92,7 +92,7 @@ describe("i18n replacers", () => {
|
|
|
92
92
|
env: Env;
|
|
93
93
|
cart: HydrogenCart;
|
|
94
94
|
storefront: Storefront<I18nLocale>;
|
|
95
|
-
customerAccount:
|
|
95
|
+
customerAccount: CustomerAccount;
|
|
96
96
|
session: AppSession;
|
|
97
97
|
waitUntil: ExecutionContext["waitUntil"];
|
|
98
98
|
}
|
|
@@ -192,6 +192,7 @@ describe("i18n replacers", () => {
|
|
|
192
192
|
*/
|
|
193
193
|
const cart = createCartHandler({
|
|
194
194
|
storefront,
|
|
195
|
+
customerAccount,
|
|
195
196
|
getCartId: cartGetIdDefault(request.headers),
|
|
196
197
|
setCartId: cartSetIdDefault(),
|
|
197
198
|
cartQueryFragment: CART_QUERY_FRAGMENT,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { readdir } from 'fs/promises';
|
|
1
|
+
import { readdir } from 'node:fs/promises';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
2
3
|
import { fileExists, mkdir, copyFile, readFile, writeFile } from '@shopify/cli-kit/node/fs';
|
|
3
4
|
import { joinPath, relativizePath, dirname, relativePath, resolvePath, basename } from '@shopify/cli-kit/node/path';
|
|
4
5
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
@@ -58,7 +59,8 @@ async function generateRoutes(options, remixConfig) {
|
|
|
58
59
|
(item) => GENERATOR_ROUTE_DIR + "/" + item
|
|
59
60
|
);
|
|
60
61
|
const formatOptions = await getCodeFormatOptions(rootDirectory);
|
|
61
|
-
const
|
|
62
|
+
const routesDirectory = joinPath(appDirectory, GENERATOR_ROUTE_DIR);
|
|
63
|
+
const localePrefix = await getLocalePrefix(routesDirectory, options);
|
|
62
64
|
const typescript = !!(options.typescript ?? await fileExists(joinPath(rootDirectory, "tsconfig.json")));
|
|
63
65
|
const routes = [];
|
|
64
66
|
for (const route of routesArray) {
|
|
@@ -73,6 +75,15 @@ async function generateRoutes(options, remixConfig) {
|
|
|
73
75
|
})
|
|
74
76
|
);
|
|
75
77
|
}
|
|
78
|
+
if (localePrefix) {
|
|
79
|
+
await copyLocaleNamelessRoute({
|
|
80
|
+
typescript,
|
|
81
|
+
localePrefix,
|
|
82
|
+
routesDirectory,
|
|
83
|
+
formatOptions,
|
|
84
|
+
adapter: options.adapter
|
|
85
|
+
});
|
|
86
|
+
}
|
|
76
87
|
return {
|
|
77
88
|
routes,
|
|
78
89
|
routeGroups,
|
|
@@ -80,14 +91,12 @@ async function generateRoutes(options, remixConfig) {
|
|
|
80
91
|
formatOptions
|
|
81
92
|
};
|
|
82
93
|
}
|
|
83
|
-
async function getLocalePrefix(
|
|
94
|
+
async function getLocalePrefix(routesDirectory, { localePrefix, routeName, v1RouteConvention }) {
|
|
84
95
|
if (localePrefix)
|
|
85
96
|
return localePrefix;
|
|
86
97
|
if (localePrefix !== void 0 || routeName === "all")
|
|
87
98
|
return;
|
|
88
|
-
const existingFiles = await readdir(
|
|
89
|
-
() => []
|
|
90
|
-
);
|
|
99
|
+
const existingFiles = await readdir(routesDirectory).catch(() => []);
|
|
91
100
|
const coreRouteWithLocaleRE = v1RouteConvention ? /^\(\$(\w+)\)$/ : /^\(\$(\w+)\)\.(_index|\$|cart).[jt]sx?$/;
|
|
92
101
|
const coreRouteWithLocale = existingFiles.find(
|
|
93
102
|
(file) => coreRouteWithLocaleRE.test(file)
|
|
@@ -161,10 +170,7 @@ async function generateProjectFile(routeFrom, {
|
|
|
161
170
|
);
|
|
162
171
|
}
|
|
163
172
|
if (adapter) {
|
|
164
|
-
templateContent = templateContent
|
|
165
|
-
/@shopify\/remix-oxygen/g,
|
|
166
|
-
adapter
|
|
167
|
-
);
|
|
173
|
+
templateContent = replaceAdapters(templateContent, adapter);
|
|
168
174
|
}
|
|
169
175
|
templateContent = await formatCode(
|
|
170
176
|
templateContent,
|
|
@@ -175,6 +181,9 @@ async function generateProjectFile(routeFrom, {
|
|
|
175
181
|
}
|
|
176
182
|
return result;
|
|
177
183
|
}
|
|
184
|
+
function replaceAdapters(templateContent, adapter) {
|
|
185
|
+
return templateContent.replace(/@shopify\/remix-oxygen/g, adapter);
|
|
186
|
+
}
|
|
178
187
|
function getDestinationRoute(routeFrom, localePrefix, options) {
|
|
179
188
|
const routePath = routeFrom.replace(GENERATOR_ROUTE_DIR + "/", "");
|
|
180
189
|
const filePrefix = localePrefix && !NO_LOCALE_PATTERNS.some((pattern) => pattern.test(routePath)) ? `($${localePrefix})` + (options.v1RouteConvention ? "/" : ".") : "";
|
|
@@ -219,5 +228,44 @@ async function renderRoutePrompt(options) {
|
|
|
219
228
|
});
|
|
220
229
|
return generateAll ? "all" : [];
|
|
221
230
|
}
|
|
231
|
+
function copyLocaleNamelessRoute({
|
|
232
|
+
typescript,
|
|
233
|
+
localePrefix,
|
|
234
|
+
...options
|
|
235
|
+
}) {
|
|
236
|
+
return copyRouteTemplate({
|
|
237
|
+
...options,
|
|
238
|
+
typescript,
|
|
239
|
+
templateName: "locale-check.ts",
|
|
240
|
+
routeName: `($${localePrefix})${typescript ? ".tsx" : ".jsx"}`
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async function copyRouteTemplate({
|
|
244
|
+
templateName,
|
|
245
|
+
routeName,
|
|
246
|
+
routesDirectory,
|
|
247
|
+
formatOptions,
|
|
248
|
+
typescript,
|
|
249
|
+
adapter
|
|
250
|
+
}) {
|
|
251
|
+
const routePath = joinPath(routesDirectory, routeName);
|
|
252
|
+
if (await fileExists(routePath))
|
|
253
|
+
return;
|
|
254
|
+
const templatePath = fileURLToPath(
|
|
255
|
+
new URL(`./templates/${templateName}`, import.meta.url)
|
|
256
|
+
);
|
|
257
|
+
if (!await fileExists(templatePath)) {
|
|
258
|
+
throw new Error("Unknown strategy");
|
|
259
|
+
}
|
|
260
|
+
let templateContent = await readFile(templatePath);
|
|
261
|
+
if (adapter) {
|
|
262
|
+
templateContent = replaceAdapters(templateContent, adapter);
|
|
263
|
+
}
|
|
264
|
+
if (!typescript) {
|
|
265
|
+
templateContent = await transpileFile(templateContent, templatePath);
|
|
266
|
+
}
|
|
267
|
+
templateContent = await formatCode(templateContent, formatOptions, routePath);
|
|
268
|
+
await writeFile(routePath, templateContent);
|
|
269
|
+
}
|
|
222
270
|
|
|
223
271
|
export { ALL_ROUTE_CHOICES, generateProjectFile, generateRoutes, getResolvedRoutes, renderRoutePrompt };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
async function loader({ params, context }) {
|
|
2
|
+
const { language, country } = context.storefront.i18n;
|
|
3
|
+
if (params.locale && params.locale.toLowerCase() !== `${language}-${country}`.toLowerCase()) {
|
|
4
|
+
throw new Response(null, { status: 404 });
|
|
5
|
+
}
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { loader };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type {LoaderFunctionArgs} from '@shopify/remix-oxygen';
|
|
2
|
+
|
|
3
|
+
export async function loader({params, context}: LoaderFunctionArgs) {
|
|
4
|
+
const {language, country} = context.storefront.i18n;
|
|
5
|
+
|
|
6
|
+
if (
|
|
7
|
+
params.locale &&
|
|
8
|
+
params.locale.toLowerCase() !== `${language}-${country}`.toLowerCase()
|
|
9
|
+
) {
|
|
10
|
+
// If the locale URL param is defined, yet we still are still at the default locale
|
|
11
|
+
// then the the locale param must be invalid, send to the 404 page
|
|
12
|
+
throw new Response(null, {status: 404});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return null;
|
|
16
|
+
}
|
package/dist/lib/shell.js
CHANGED
|
@@ -155,7 +155,7 @@ async function createShortcutsForWindows() {
|
|
|
155
155
|
return shells;
|
|
156
156
|
}
|
|
157
157
|
async function getCliCommand(directory = process.cwd(), forcePkgManager) {
|
|
158
|
-
if (
|
|
158
|
+
if (await hasCliAlias()) {
|
|
159
159
|
return ALIAS_NAME;
|
|
160
160
|
}
|
|
161
161
|
let cli = "npx";
|
|
@@ -67,15 +67,25 @@ ${colors.dim(
|
|
|
67
67
|
async function applyTemplateDiff(targetDirectory, diffDirectory, templateDir = getStarterDir()) {
|
|
68
68
|
const createFilter = (re) => (filepath) => !re.test(relativePath(templateDir, filepath));
|
|
69
69
|
await copy(templateDir, targetDirectory, {
|
|
70
|
-
filter: createFilter(
|
|
70
|
+
filter: createFilter(
|
|
71
|
+
/(^|\/|\\)(dist|node_modules|\.cache|CHANGELOG\.md)(\/|\\|$)/i
|
|
72
|
+
)
|
|
71
73
|
});
|
|
72
74
|
await copy(diffDirectory, targetDirectory, {
|
|
73
75
|
filter: createFilter(
|
|
74
|
-
/
|
|
76
|
+
/(^|\/|\\)(dist|node_modules|\.cache|package\.json|tsconfig\.json)(\/|\\|$)/i
|
|
75
77
|
)
|
|
76
78
|
});
|
|
77
79
|
await mergePackageJson(diffDirectory, targetDirectory, {
|
|
78
|
-
|
|
80
|
+
onResult: (pkgJson) => {
|
|
81
|
+
for (const key of ["build", "dev"]) {
|
|
82
|
+
const scriptLine = pkgJson.scripts?.[key];
|
|
83
|
+
if (pkgJson.scripts?.[key] && typeof scriptLine === "string") {
|
|
84
|
+
pkgJson.scripts[key] = scriptLine.replace(/\s+--diff/, "");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return pkgJson;
|
|
88
|
+
}
|
|
79
89
|
});
|
|
80
90
|
}
|
|
81
91
|
async function copyDiffBuild(targetDirectory, diffDirectory) {
|
|
@@ -64,13 +64,13 @@ function RequestDetails({
|
|
|
64
64
|
/* @__PURE__ */ jsx("div", { id: "tab1-panel", className: `tabPanel${activeTabClass(1)}`, children: /* @__PURE__ */ jsxs("div", { className: "grid-layout", children: [
|
|
65
65
|
/* @__PURE__ */ jsx(DetailsRow, { rowName: "Name", value: requestInfo.displayName }),
|
|
66
66
|
/* @__PURE__ */ jsx(DetailsRow, { rowName: "Request URL", value: requestInfo.url }),
|
|
67
|
-
/* @__PURE__ */ jsx(
|
|
67
|
+
requestInfo.responseInit ? /* @__PURE__ */ jsx(
|
|
68
68
|
DetailsRow,
|
|
69
69
|
{
|
|
70
70
|
rowName: "Status",
|
|
71
71
|
value: `${requestInfo.responseInit?.status} ${requestInfo.responseInit?.statusText}`
|
|
72
72
|
}
|
|
73
|
-
),
|
|
73
|
+
) : null,
|
|
74
74
|
/* @__PURE__ */ jsx(
|
|
75
75
|
DetailsRow,
|
|
76
76
|
{
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "7.
|
|
2
|
+
"version": "7.1.0",
|
|
3
3
|
"commands": {
|
|
4
4
|
"hydrogen:build": {
|
|
5
5
|
"id": "hydrogen:build",
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
"sourcemap": {
|
|
20
20
|
"name": "sourcemap",
|
|
21
21
|
"type": "boolean",
|
|
22
|
-
"description": "
|
|
22
|
+
"description": "Controls whether sourcemaps are generated. Default to true, use `--no-sourcemaps` to disable.",
|
|
23
23
|
"allowNo": true
|
|
24
24
|
},
|
|
25
25
|
"bundle-stats": {
|
|
26
26
|
"name": "bundle-stats",
|
|
27
27
|
"type": "boolean",
|
|
28
|
-
"description": "Show a bundle size summary after building.",
|
|
28
|
+
"description": "Show a bundle size summary after building. Defaults to true, use `--no-bundle-stats` to disable.",
|
|
29
29
|
"allowNo": true
|
|
30
30
|
},
|
|
31
31
|
"lockfile-check": {
|
|
32
32
|
"name": "lockfile-check",
|
|
33
33
|
"type": "boolean",
|
|
34
|
-
"description": "Checks that there is exactly 1 valid lockfile in the project.",
|
|
34
|
+
"description": "Checks that there is exactly 1 valid lockfile in the project. Defaults to true, use `--no-lockfile-check` to disable.",
|
|
35
35
|
"allowNo": true
|
|
36
36
|
},
|
|
37
37
|
"disable-route-warning": {
|
|
@@ -149,6 +149,13 @@
|
|
|
149
149
|
"required": false,
|
|
150
150
|
"multiple": false
|
|
151
151
|
},
|
|
152
|
+
"env-file": {
|
|
153
|
+
"name": "env-file",
|
|
154
|
+
"type": "option",
|
|
155
|
+
"description": "Path to an environment file to override existing environment variables for the deployment.",
|
|
156
|
+
"required": false,
|
|
157
|
+
"multiple": false
|
|
158
|
+
},
|
|
152
159
|
"preview": {
|
|
153
160
|
"name": "preview",
|
|
154
161
|
"type": "boolean",
|
|
@@ -164,6 +171,13 @@
|
|
|
164
171
|
"required": false,
|
|
165
172
|
"allowNo": false
|
|
166
173
|
},
|
|
174
|
+
"no-verify": {
|
|
175
|
+
"name": "no-verify",
|
|
176
|
+
"type": "boolean",
|
|
177
|
+
"description": "Skip the routability verification step after deployment.",
|
|
178
|
+
"required": false,
|
|
179
|
+
"allowNo": false
|
|
180
|
+
},
|
|
167
181
|
"auth-bypass-token": {
|
|
168
182
|
"name": "auth-bypass-token",
|
|
169
183
|
"type": "boolean",
|
|
@@ -171,6 +185,19 @@
|
|
|
171
185
|
"required": false,
|
|
172
186
|
"allowNo": false
|
|
173
187
|
},
|
|
188
|
+
"build-command": {
|
|
189
|
+
"name": "build-command",
|
|
190
|
+
"type": "option",
|
|
191
|
+
"description": "Specify a build command to run before deploying. If not specified, `shopify hydrogen build` will be used.",
|
|
192
|
+
"required": false,
|
|
193
|
+
"multiple": false
|
|
194
|
+
},
|
|
195
|
+
"lockfile-check": {
|
|
196
|
+
"name": "lockfile-check",
|
|
197
|
+
"type": "boolean",
|
|
198
|
+
"description": "Checks that there is exactly 1 valid lockfile in the project. Defaults to true, use `--no-lockfile-check` to disable.",
|
|
199
|
+
"allowNo": true
|
|
200
|
+
},
|
|
174
201
|
"path": {
|
|
175
202
|
"name": "path",
|
|
176
203
|
"type": "option",
|
|
@@ -184,12 +211,12 @@
|
|
|
184
211
|
"description": "Shop URL. It can be the shop prefix (janes-apparel) or the full myshopify.com URL (janes-apparel.myshopify.com, https://janes-apparel.myshopify.com).",
|
|
185
212
|
"multiple": false
|
|
186
213
|
},
|
|
187
|
-
"
|
|
188
|
-
"name": "
|
|
214
|
+
"json-output": {
|
|
215
|
+
"name": "json-output",
|
|
189
216
|
"type": "boolean",
|
|
190
|
-
"description": "
|
|
217
|
+
"description": "Create a JSON file containing the deployment details in CI environments. Defaults to true, use `--no-json-output` to disable.",
|
|
191
218
|
"required": false,
|
|
192
|
-
"allowNo":
|
|
219
|
+
"allowNo": true
|
|
193
220
|
},
|
|
194
221
|
"token": {
|
|
195
222
|
"name": "token",
|
|
@@ -777,6 +804,12 @@
|
|
|
777
804
|
"description": "Generate TypeScript files",
|
|
778
805
|
"allowNo": false
|
|
779
806
|
},
|
|
807
|
+
"locale-param": {
|
|
808
|
+
"name": "locale-param",
|
|
809
|
+
"type": "option",
|
|
810
|
+
"description": "The param name in Remix routes for the i18n locale, if any. Example: `locale` becomes ($locale).",
|
|
811
|
+
"multiple": false
|
|
812
|
+
},
|
|
780
813
|
"force": {
|
|
781
814
|
"name": "force",
|
|
782
815
|
"type": "boolean",
|
|
@@ -834,6 +867,12 @@
|
|
|
834
867
|
"description": "Generate TypeScript files",
|
|
835
868
|
"allowNo": false
|
|
836
869
|
},
|
|
870
|
+
"locale-param": {
|
|
871
|
+
"name": "locale-param",
|
|
872
|
+
"type": "option",
|
|
873
|
+
"description": "The param name in Remix routes for the i18n locale, if any. Example: `locale` becomes ($locale).",
|
|
874
|
+
"multiple": false
|
|
875
|
+
},
|
|
837
876
|
"force": {
|
|
838
877
|
"name": "force",
|
|
839
878
|
"type": "boolean",
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public",
|
|
5
5
|
"@shopify:registry": "https://registry.npmjs.org"
|
|
6
6
|
},
|
|
7
|
-
"version": "7.
|
|
7
|
+
"version": "7.1.0",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"test:watch": "cross-env SHOPIFY_UNIT_TEST=1 vitest --test-timeout=20000"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@remix-run/dev": "^2.
|
|
19
|
+
"@remix-run/dev": "^2.6.0",
|
|
20
20
|
"@types/diff": "^5.0.2",
|
|
21
21
|
"@types/fs-extra": "^11.0.1",
|
|
22
22
|
"@types/gunzip-maybe": "^1.4.0",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@ast-grep/napi": "0.11.0",
|
|
37
|
-
"@graphql-codegen/cli": "5.0.
|
|
37
|
+
"@graphql-codegen/cli": "5.0.1",
|
|
38
38
|
"@oclif/core": "2.11.7",
|
|
39
39
|
"@shopify/cli-kit": "3.52.0",
|
|
40
|
-
"@shopify/hydrogen-codegen": "^0.2.
|
|
40
|
+
"@shopify/hydrogen-codegen": "^0.2.1",
|
|
41
41
|
"@shopify/mini-oxygen": "^2.2.5",
|
|
42
|
-
"@shopify/oxygen-cli": "^4.
|
|
42
|
+
"@shopify/oxygen-cli": "^4.1.0",
|
|
43
43
|
"ansi-escapes": "^6.2.0",
|
|
44
44
|
"cli-truncate": "^4.0.0",
|
|
45
45
|
"diff": "^5.1.0",
|