@shopify/cli-hydrogen 7.1.2 → 8.0.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-vite.js +19 -10
- package/dist/commands/hydrogen/build.js +10 -2
- package/dist/commands/hydrogen/check.js +1 -0
- package/dist/commands/hydrogen/codegen.js +1 -0
- package/dist/commands/hydrogen/customer-account/push.js +170 -0
- package/dist/commands/hydrogen/debug/cpu.js +3 -0
- package/dist/commands/hydrogen/deploy.js +121 -36
- package/dist/commands/hydrogen/dev-vite.js +128 -59
- package/dist/commands/hydrogen/dev.js +108 -51
- package/dist/commands/hydrogen/env/list.js +7 -8
- package/dist/commands/hydrogen/env/pull.js +17 -1
- package/dist/commands/hydrogen/env/{push__unstable.js → push.js} +23 -50
- package/dist/commands/hydrogen/generate/route.js +1 -0
- package/dist/commands/hydrogen/init.js +45 -17
- package/dist/commands/hydrogen/link.js +20 -4
- package/dist/commands/hydrogen/list.js +1 -0
- package/dist/commands/hydrogen/login.js +1 -0
- package/dist/commands/hydrogen/logout.js +1 -0
- package/dist/commands/hydrogen/preview.js +31 -16
- package/dist/commands/hydrogen/setup/css.js +8 -1
- package/dist/commands/hydrogen/setup/markets.js +1 -0
- package/dist/commands/hydrogen/setup/vite.js +244 -138
- package/dist/commands/hydrogen/setup.js +21 -22
- package/dist/commands/hydrogen/shortcut.js +10 -0
- package/dist/commands/hydrogen/unlink.js +1 -0
- package/dist/commands/hydrogen/upgrade.js +2 -1
- package/dist/generator-templates/assets/vite/package.json +3 -4
- package/dist/generator-templates/assets/vite/vite.config.js +10 -2
- package/dist/generator-templates/starter/CHANGELOG.md +89 -0
- package/dist/generator-templates/starter/README.md +3 -44
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -0
- package/dist/generator-templates/starter/app/lib/fragments.ts +2 -0
- package/dist/generator-templates/starter/app/root.tsx +2 -5
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/account.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/collections.all.tsx +160 -0
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +1 -2
- package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +6 -3
- package/dist/generator-templates/starter/{remix.env.d.ts → env.d.ts} +8 -2
- package/dist/generator-templates/starter/package.json +14 -9
- package/dist/generator-templates/starter/server.ts +2 -1
- package/dist/generator-templates/starter/storefrontapi.generated.d.ts +59 -3
- package/dist/generator-templates/starter/vite.config.ts +21 -0
- package/dist/{commands/hydrogen/init.d.ts → init.d.ts} +11 -3
- package/dist/lib/check-lockfile.js +12 -18
- package/dist/lib/codegen.js +37 -13
- package/dist/lib/common.js +50 -0
- package/dist/lib/cpu-profiler.js +4 -1
- package/dist/lib/dev-shared.js +97 -0
- package/dist/lib/environment-variables.js +51 -30
- package/dist/lib/file.js +8 -1
- package/dist/lib/flags.js +37 -16
- package/dist/lib/graphql/admin/customer-application-update.js +29 -0
- package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
- package/dist/lib/graphql/admin/list-environments.js +1 -0
- package/dist/lib/graphql/admin/pull-variables.js +4 -4
- package/dist/lib/graphql/admin/test-helper.js +37 -0
- package/dist/lib/log.js +86 -13
- package/dist/lib/mini-oxygen/common.js +19 -33
- package/dist/lib/mini-oxygen/index.js +6 -2
- package/dist/lib/mini-oxygen/node.js +43 -31
- package/dist/lib/mini-oxygen/workerd.js +72 -165
- package/dist/lib/missing-routes.js +1 -1
- package/dist/lib/onboarding/common.js +82 -70
- package/dist/lib/onboarding/local.js +19 -9
- package/dist/lib/onboarding/remote.js +35 -30
- package/dist/lib/package-managers.js +24 -0
- package/dist/lib/remix-config.js +17 -1
- package/dist/lib/request-events.js +6 -1
- package/dist/lib/setups/i18n/replacers.js +9 -6
- package/dist/lib/setups/routes/generate.js +1 -0
- package/dist/lib/shell.js +2 -1
- package/dist/lib/shopify-config.js +19 -1
- package/dist/lib/template-diff.js +36 -15
- package/dist/lib/template-downloader.js +35 -5
- package/dist/lib/transpile/morph/typedefs.js +5 -2
- package/dist/lib/transpile/project.js +8 -4
- package/dist/lib/tunneling.js +44 -0
- package/dist/lib/virtual-routes.js +1 -1
- package/dist/lib/vite-config.js +39 -9
- package/oclif.manifest.json +711 -498
- package/package.json +32 -24
- package/dist/commands/hydrogen/deploy.test.js +0 -553
- package/dist/commands/hydrogen/env/list.test.js +0 -148
- package/dist/commands/hydrogen/env/pull.test.js +0 -207
- package/dist/commands/hydrogen/env/push__unstable.test.js +0 -383
- package/dist/commands/hydrogen/generate/route.test.js +0 -43
- package/dist/commands/hydrogen/init.test.js +0 -641
- package/dist/commands/hydrogen/link.test.js +0 -187
- package/dist/commands/hydrogen/list.test.js +0 -111
- package/dist/commands/hydrogen/setup.test.js +0 -61
- package/dist/commands/hydrogen/shortcut.test.js +0 -30
- package/dist/commands/hydrogen/unlink.test.js +0 -36
- package/dist/commands/hydrogen/upgrade.test.js +0 -786
- package/dist/generator-templates/starter/remix.config.js +0 -24
- package/dist/lib/auth.test.js +0 -157
- package/dist/lib/check-lockfile.test.js +0 -81
- package/dist/lib/check-version.test.js +0 -86
- package/dist/lib/environment-variables.test.js +0 -149
- package/dist/lib/file.test.js +0 -68
- package/dist/lib/flags.test.js +0 -43
- package/dist/lib/get-oxygen-deployment-data.test.js +0 -120
- package/dist/lib/gid.test.js +0 -15
- package/dist/lib/graphql/admin/client.test.js +0 -76
- package/dist/lib/graphql/admin/create-storefront.test.js +0 -64
- package/dist/lib/graphql/admin/link-storefront.test.js +0 -38
- package/dist/lib/graphql/admin/list-environments.test.js +0 -44
- package/dist/lib/graphql/admin/list-storefronts.test.js +0 -44
- package/dist/lib/graphql/admin/pull-variables.test.js +0 -43
- package/dist/lib/graphql/business-platform/user-account.test.js +0 -80
- package/dist/lib/log.test.js +0 -92
- package/dist/lib/mini-oxygen/assets.js +0 -134
- package/dist/lib/mini-oxygen/mini-oxygen.test.js +0 -214
- package/dist/lib/mini-oxygen/workerd-inspector-logs.js +0 -227
- package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +0 -200
- package/dist/lib/mini-oxygen/workerd-inspector.js +0 -219
- package/dist/lib/missing-routes.test.js +0 -45
- package/dist/lib/remix-version-check.test.js +0 -39
- package/dist/lib/remix-version-interop.test.js +0 -13
- package/dist/lib/setups/i18n/domains.test.js +0 -39
- package/dist/lib/setups/i18n/replacers.test.js +0 -261
- package/dist/lib/setups/i18n/subdomains.test.js +0 -39
- package/dist/lib/setups/i18n/subfolders.test.js +0 -39
- package/dist/lib/setups/routes/generate.test.js +0 -296
- package/dist/lib/shell.test.js +0 -111
- package/dist/lib/shopify-config.test.js +0 -199
- package/dist/lib/string.test.js +0 -16
- package/dist/lib/virtual-routes.test.js +0 -49
- package/dist/lib/vite/hydrogen-middleware.js +0 -82
- package/dist/lib/vite/mini-oxygen.js +0 -152
- package/dist/lib/vite/plugins.d.ts +0 -27
- package/dist/lib/vite/plugins.js +0 -139
- package/dist/lib/vite/shared.js +0 -10
- package/dist/lib/vite/utils.js +0 -55
- package/dist/lib/vite/worker-entry.js +0 -1518
- /package/dist/generator-templates/starter/{.eslintrc.js → .eslintrc.cjs} +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const packageManagers = [
|
|
2
|
+
{
|
|
3
|
+
name: "npm",
|
|
4
|
+
lockfile: "package-lock.json",
|
|
5
|
+
installCommand: "npm ci"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
name: "yarn",
|
|
9
|
+
lockfile: "yarn.lock",
|
|
10
|
+
installCommand: "yarn install --frozen-lockfile"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "pnpm",
|
|
14
|
+
lockfile: "pnpm-lock.yaml",
|
|
15
|
+
installCommand: "pnpm install --frozen-lockfile"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "bun",
|
|
19
|
+
lockfile: "bun.lockb",
|
|
20
|
+
installCommand: "bun install --frozen-lockfile"
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export { packageManagers };
|
package/dist/lib/remix-config.js
CHANGED
|
@@ -7,7 +7,13 @@ import { outputWarn } from '@shopify/cli-kit/node/output';
|
|
|
7
7
|
import { fileExists } from '@shopify/cli-kit/node/fs';
|
|
8
8
|
import { muteRemixLogs } from './log.js';
|
|
9
9
|
import { getRequiredRemixVersion } from './remix-version-check.js';
|
|
10
|
+
import { findFileWithExtension } from './file.js';
|
|
11
|
+
import { getViteConfig } from './vite-config.js';
|
|
10
12
|
|
|
13
|
+
async function hasRemixConfigFile(root) {
|
|
14
|
+
const result = await findFileWithExtension(root, "remix.config");
|
|
15
|
+
return !!result.filepath;
|
|
16
|
+
}
|
|
11
17
|
const BUILD_DIR = "dist";
|
|
12
18
|
const CLIENT_SUBDIR = "client";
|
|
13
19
|
const WORKER_SUBDIR = "worker";
|
|
@@ -33,7 +39,17 @@ function handleRemixImportFail() {
|
|
|
33
39
|
`Please make sure you have \`@remix-run/dev@${remixVersion}\` installed and all the other Remix packages have the same version.`
|
|
34
40
|
);
|
|
35
41
|
}
|
|
42
|
+
function getRawRemixConfig(root) {
|
|
43
|
+
return findFileWithExtension(root, "remix.config").then(({ filepath }) => {
|
|
44
|
+
if (!filepath)
|
|
45
|
+
throw new AbortError("No remix.config.js file found.");
|
|
46
|
+
return createRequire(import.meta.url)(filepath);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
36
49
|
async function getRemixConfig(root, mode = process.env.NODE_ENV) {
|
|
50
|
+
if (!await hasRemixConfigFile(root)) {
|
|
51
|
+
return (await getViteConfig(root)).remixConfig;
|
|
52
|
+
}
|
|
37
53
|
await muteRemixLogs();
|
|
38
54
|
const { readConfig } = await import('@remix-run/dev/dist/config.js').catch(
|
|
39
55
|
handleRemixImportFail
|
|
@@ -144,4 +160,4 @@ async function assertEntryFileExists(root, fileRelative) {
|
|
|
144
160
|
}
|
|
145
161
|
}
|
|
146
162
|
|
|
147
|
-
export { assertOxygenChecks, getProjectPaths, getRemixConfig, handleRemixImportFail };
|
|
163
|
+
export { assertOxygenChecks, getProjectPaths, getRawRemixConfig, getRemixConfig, handleRemixImportFail, hasRemixConfigFile };
|
|
@@ -9,7 +9,12 @@ let ResponseConstructor;
|
|
|
9
9
|
function setConstructors(constructors) {
|
|
10
10
|
ResponseConstructor = constructors.Response;
|
|
11
11
|
}
|
|
12
|
-
const DEV_ROUTES = /* @__PURE__ */ new Set([
|
|
12
|
+
const DEV_ROUTES = /* @__PURE__ */ new Set([
|
|
13
|
+
"/graphiql",
|
|
14
|
+
"/graphiql/customer-account.schema.json",
|
|
15
|
+
"/subrequest-profiler",
|
|
16
|
+
"/debug-network-server"
|
|
17
|
+
]);
|
|
13
18
|
const EVENT_MAP = {
|
|
14
19
|
request: "Request",
|
|
15
20
|
subrequest: "Sub request"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
2
|
-
import { joinPath } from '@shopify/cli-kit/node/path';
|
|
2
|
+
import { joinPath, resolvePath } from '@shopify/cli-kit/node/path';
|
|
3
3
|
import { fileExists } from '@shopify/cli-kit/node/fs';
|
|
4
4
|
import { replaceFileContent, findFileWithExtension } from '../../file.js';
|
|
5
5
|
import { importLangAstGrep } from '../../ast.js';
|
|
@@ -147,9 +147,12 @@ ${localeExtractFn}
|
|
|
147
147
|
});
|
|
148
148
|
}
|
|
149
149
|
async function replaceRemixEnv({ rootDirectory }, formatConfig, localeExtractImpl) {
|
|
150
|
-
|
|
151
|
-
if (!await fileExists(
|
|
152
|
-
|
|
150
|
+
let envPath = joinPath(rootDirectory, "env.d.ts");
|
|
151
|
+
if (!await fileExists(envPath)) {
|
|
152
|
+
envPath = "remix.env.d.ts";
|
|
153
|
+
if (!await fileExists(envPath)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
const i18nType = localeExtractImpl.match(
|
|
155
158
|
/^(export )?(type \w+ =\s+\{.*?\};)\n/ms
|
|
@@ -158,7 +161,7 @@ async function replaceRemixEnv({ rootDirectory }, formatConfig, localeExtractImp
|
|
|
158
161
|
if (!i18nTypeName) {
|
|
159
162
|
return;
|
|
160
163
|
}
|
|
161
|
-
await replaceFileContent(
|
|
164
|
+
await replaceFileContent(envPath, formatConfig, async (content) => {
|
|
162
165
|
if (content.includes(`Storefront<`))
|
|
163
166
|
return;
|
|
164
167
|
const astGrep = await importLangAstGrep("ts");
|
|
@@ -237,7 +240,7 @@ async function findEntryFile({
|
|
|
237
240
|
serverEntryPoint = "server"
|
|
238
241
|
}) {
|
|
239
242
|
const match = serverEntryPoint.match(/\.([jt]sx?)$/)?.[1];
|
|
240
|
-
const { filepath, astType } = match ? { filepath:
|
|
243
|
+
const { filepath, astType } = match ? { filepath: resolvePath(rootDirectory, serverEntryPoint), astType: match } : await findFileWithExtension(rootDirectory, serverEntryPoint);
|
|
241
244
|
if (!filepath || !astType) {
|
|
242
245
|
throw new AbortError(
|
|
243
246
|
`Could not find a server entry point at ${serverEntryPoint}`
|
|
@@ -199,6 +199,7 @@ async function findRouteDependencies(routeFilePath, appDirectory) {
|
|
|
199
199
|
for (let [, , match] of importMatches) {
|
|
200
200
|
if (!match || !/^(\.|~)/.test(match))
|
|
201
201
|
continue;
|
|
202
|
+
match = match.replace(/\?[a-z.]+$/, "");
|
|
202
203
|
match = match.replace(
|
|
203
204
|
"~",
|
|
204
205
|
// import from '~/components/...'
|
package/dist/lib/shell.js
CHANGED
|
@@ -113,7 +113,8 @@ async function createPlatformShortcut() {
|
|
|
113
113
|
}
|
|
114
114
|
const BASH_ZSH_COMMAND = `
|
|
115
115
|
# Shopify Hydrogen alias to local projects
|
|
116
|
-
alias ${ALIAS_NAME}='$(npm prefix -s)/node_modules/.bin/shopify hydrogen'
|
|
116
|
+
alias ${ALIAS_NAME}='$(npm prefix -s)/node_modules/.bin/shopify hydrogen'
|
|
117
|
+
`;
|
|
117
118
|
const FISH_FUNCTION = `
|
|
118
119
|
function ${ALIAS_NAME} --wraps='shopify hydrogen' --description 'Shortcut for the Hydrogen CLI'
|
|
119
120
|
set npmPrefix (npm prefix -s)
|
|
@@ -87,5 +87,23 @@ async function ensureShopifyGitIgnore(root) {
|
|
|
87
87
|
return false;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
async function setCustomerAccountConfig(root, customerAccountConfig) {
|
|
91
|
+
try {
|
|
92
|
+
const filePath = resolvePath(root, SHOPIFY_DIR, SHOPIFY_DIR_PROJECT);
|
|
93
|
+
const existingConfig = JSON.parse(await readFile(filePath));
|
|
94
|
+
const config = {
|
|
95
|
+
...existingConfig,
|
|
96
|
+
storefront: {
|
|
97
|
+
...existingConfig.storefront,
|
|
98
|
+
customerAccountConfig
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
await writeFile(filePath, JSON.stringify(config));
|
|
102
|
+
await ensureShopifyGitIgnore(root);
|
|
103
|
+
return config;
|
|
104
|
+
} catch {
|
|
105
|
+
throw new AbortError("Project configuration could not be found.");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
90
108
|
|
|
91
|
-
export { SHOPIFY_DIR, SHOPIFY_DIR_PROJECT, ensureShopifyGitIgnore, getConfig, resetConfig, setStorefront, setUserAccount, unsetStorefront };
|
|
109
|
+
export { SHOPIFY_DIR, SHOPIFY_DIR_PROJECT, ensureShopifyGitIgnore, getConfig, resetConfig, setCustomerAccountConfig, setStorefront, setUserAccount, unsetStorefront };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { rmdirSync } from 'node:fs';
|
|
2
2
|
import { temporaryDirectory } from 'tempy';
|
|
3
|
-
import { createSymlink, copy
|
|
4
|
-
import { copyFile, removeFile } from '@shopify/cli-kit/node/fs';
|
|
3
|
+
import { createSymlink, copy } from 'fs-extra/esm';
|
|
4
|
+
import { copyFile, removeFile, fileExists } from '@shopify/cli-kit/node/fs';
|
|
5
5
|
import { joinPath, relativePath } from '@shopify/cli-kit/node/path';
|
|
6
6
|
import { readAndParsePackageJson } from '@shopify/cli-kit/node/node-package-manager';
|
|
7
7
|
import colors from '@shopify/cli-kit/node/colors';
|
|
@@ -66,9 +66,10 @@ ${colors.dim(
|
|
|
66
66
|
return targetDirectory;
|
|
67
67
|
}
|
|
68
68
|
async function applyTemplateDiff(targetDirectory, diffDirectory, templateDir = getStarterDir()) {
|
|
69
|
-
const
|
|
69
|
+
const diffPkgJson = await readAndParsePackageJson(
|
|
70
70
|
joinPath(diffDirectory, "package.json")
|
|
71
71
|
);
|
|
72
|
+
const diffOptions = diffPkgJson["h2:diff"] ?? {};
|
|
72
73
|
const createFilter = (re, skipFiles) => (filepath) => {
|
|
73
74
|
const filename = relativePath(templateDir, filepath);
|
|
74
75
|
return !re.test(filename) && !skipFiles?.includes(filename);
|
|
@@ -76,7 +77,7 @@ async function applyTemplateDiff(targetDirectory, diffDirectory, templateDir = g
|
|
|
76
77
|
await copy(templateDir, targetDirectory, {
|
|
77
78
|
filter: createFilter(
|
|
78
79
|
/(^|\/|\\)(dist|node_modules|\.cache|.turbo|CHANGELOG\.md)(\/|\\|$)/i,
|
|
79
|
-
|
|
80
|
+
diffOptions.skipFiles || []
|
|
80
81
|
)
|
|
81
82
|
});
|
|
82
83
|
await copy(diffDirectory, targetDirectory, {
|
|
@@ -86,29 +87,49 @@ async function applyTemplateDiff(targetDirectory, diffDirectory, templateDir = g
|
|
|
86
87
|
});
|
|
87
88
|
await mergePackageJson(diffDirectory, targetDirectory, {
|
|
88
89
|
ignoredKeys: ["h2:diff"],
|
|
89
|
-
onResult: (
|
|
90
|
+
onResult: (pkgJson) => {
|
|
90
91
|
for (const key of ["build", "dev"]) {
|
|
91
|
-
const scriptLine =
|
|
92
|
-
if (
|
|
93
|
-
|
|
92
|
+
const scriptLine = pkgJson.scripts?.[key];
|
|
93
|
+
if (pkgJson.scripts?.[key] && typeof scriptLine === "string") {
|
|
94
|
+
pkgJson.scripts[key] = scriptLine.replace(/\s+--diff/, "");
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
if (diffOptions.skipDependencies && pkgJson.dependencies) {
|
|
98
|
+
for (const dep of diffOptions.skipDependencies) {
|
|
99
|
+
delete pkgJson.dependencies[dep];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (diffOptions.skipDevDependencies && pkgJson.devDependencies) {
|
|
103
|
+
for (const devDep of diffOptions.skipDevDependencies) {
|
|
104
|
+
delete pkgJson.devDependencies[devDep];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return pkgJson;
|
|
97
108
|
}
|
|
98
109
|
});
|
|
99
110
|
}
|
|
100
|
-
async function copyDiffBuild(
|
|
101
|
-
const
|
|
102
|
-
await
|
|
111
|
+
async function copyDiffBuild(generatedDirectory, diffDirectory) {
|
|
112
|
+
const target = joinPath(diffDirectory, "dist");
|
|
113
|
+
await removeFile(target);
|
|
103
114
|
await Promise.all([
|
|
104
|
-
copy(joinPath(
|
|
115
|
+
copy(joinPath(generatedDirectory, "dist"), target, {
|
|
105
116
|
overwrite: true
|
|
106
117
|
}),
|
|
107
118
|
copyFile(
|
|
108
|
-
joinPath(
|
|
119
|
+
joinPath(generatedDirectory, ".env"),
|
|
109
120
|
joinPath(diffDirectory, ".env")
|
|
110
121
|
)
|
|
111
122
|
]);
|
|
112
123
|
}
|
|
124
|
+
async function copyShopifyConfig(generatedDirectory, diffDirectory) {
|
|
125
|
+
const source = joinPath(generatedDirectory, ".shopify");
|
|
126
|
+
if (!await fileExists(source))
|
|
127
|
+
return;
|
|
128
|
+
const target = joinPath(diffDirectory, ".shopify");
|
|
129
|
+
await removeFile(target);
|
|
130
|
+
await copy(joinPath(generatedDirectory, ".shopify"), target, {
|
|
131
|
+
overwrite: true
|
|
132
|
+
});
|
|
133
|
+
}
|
|
113
134
|
|
|
114
|
-
export { applyTemplateDiff, copyDiffBuild, prepareDiffDirectory };
|
|
135
|
+
export { applyTemplateDiff, copyDiffBuild, copyShopifyConfig, prepareDiffDirectory };
|
|
@@ -4,9 +4,12 @@ import { pipeline } from 'stream/promises';
|
|
|
4
4
|
import gunzipMaybe from 'gunzip-maybe';
|
|
5
5
|
import { extract } from 'tar-fs';
|
|
6
6
|
import { fetch } from '@shopify/cli-kit/node/http';
|
|
7
|
-
import {
|
|
7
|
+
import { parseGitHubRepositoryURL } from '@shopify/cli-kit/node/github';
|
|
8
|
+
import { fileExists, mkdir, rmdir } from '@shopify/cli-kit/node/fs';
|
|
8
9
|
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
9
10
|
import { getSkeletonSourceDir } from './build.js';
|
|
11
|
+
import { joinPath } from '@shopify/cli-kit/node/path';
|
|
12
|
+
import { downloadGitRepository } from '@shopify/cli-kit/node/git';
|
|
10
13
|
|
|
11
14
|
const REPO_RELEASES_URL = `https://api.github.com/repos/shopify/hydrogen/releases/latest`;
|
|
12
15
|
const getTryMessage = (status) => status === 403 ? `If you are using a VPN, WARP, or similar service, consider disabling it momentarily.` : void 0;
|
|
@@ -25,7 +28,7 @@ async function getLatestReleaseDownloadUrl(signal) {
|
|
|
25
28
|
url: release.tarball_url
|
|
26
29
|
};
|
|
27
30
|
}
|
|
28
|
-
async function
|
|
31
|
+
async function downloadMonorepoTarball(url, storageDir, signal) {
|
|
29
32
|
const response = await fetch(url, { signal });
|
|
30
33
|
if (!response.ok || response.status >= 400) {
|
|
31
34
|
throw new AbortError(
|
|
@@ -48,7 +51,7 @@ async function downloadTarball(url, storageDir, signal) {
|
|
|
48
51
|
})
|
|
49
52
|
);
|
|
50
53
|
}
|
|
51
|
-
async function
|
|
54
|
+
async function downloadMonorepoTemplates({
|
|
52
55
|
signal
|
|
53
56
|
} = {}) {
|
|
54
57
|
if (process.env.LOCAL_DEV) {
|
|
@@ -69,7 +72,7 @@ async function getLatestTemplates({
|
|
|
69
72
|
}
|
|
70
73
|
const templateStorageVersionPath = path.join(templateStoragePath, version);
|
|
71
74
|
if (!await fileExists(templateStorageVersionPath)) {
|
|
72
|
-
await
|
|
75
|
+
await downloadMonorepoTarball(url, templateStorageVersionPath, signal);
|
|
73
76
|
}
|
|
74
77
|
return {
|
|
75
78
|
version,
|
|
@@ -87,5 +90,32 @@ Please check your internet connection and the following error:
|
|
|
87
90
|
);
|
|
88
91
|
}
|
|
89
92
|
}
|
|
93
|
+
async function downloadExternalRepo(appTemplate, signal) {
|
|
94
|
+
const parsed = parseGitHubRepositoryURL(appTemplate);
|
|
95
|
+
if (parsed.isErr()) {
|
|
96
|
+
throw new AbortError(parsed.error.message);
|
|
97
|
+
}
|
|
98
|
+
const externalTemplates = fileURLToPath(
|
|
99
|
+
new URL("../external-templates", import.meta.url)
|
|
100
|
+
);
|
|
101
|
+
if (!await fileExists(externalTemplates)) {
|
|
102
|
+
await mkdir(externalTemplates);
|
|
103
|
+
}
|
|
104
|
+
const result = parsed.value;
|
|
105
|
+
const templateDir = joinPath(
|
|
106
|
+
externalTemplates,
|
|
107
|
+
result.full.replace(/^https?:\/\//, "").replace(/[^\w]+/, "_")
|
|
108
|
+
);
|
|
109
|
+
if (await fileExists(templateDir)) {
|
|
110
|
+
await rmdir(templateDir, { force: true });
|
|
111
|
+
}
|
|
112
|
+
await downloadGitRepository({
|
|
113
|
+
repoUrl: result.full,
|
|
114
|
+
destination: templateDir,
|
|
115
|
+
shallow: true
|
|
116
|
+
});
|
|
117
|
+
await rmdir(joinPath(templateDir, ".git"), { force: true });
|
|
118
|
+
return { templateDir };
|
|
119
|
+
}
|
|
90
120
|
|
|
91
|
-
export {
|
|
121
|
+
export { downloadExternalRepo, downloadMonorepoTemplates };
|
|
@@ -26,13 +26,16 @@ function generateTypeDefs(sourceFile, code) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
typedefs.push("");
|
|
29
|
+
const knownGenerics = {
|
|
30
|
+
MetaFunction: "T"
|
|
31
|
+
};
|
|
29
32
|
typedefsFromImports.forEach((typeElements, moduleSpecifier) => {
|
|
30
33
|
for (const typeElement of typeElements) {
|
|
31
34
|
if (typeElement === "SerializeFrom")
|
|
32
35
|
continue;
|
|
33
|
-
const hasGeneric = typeElement
|
|
36
|
+
const hasGeneric = !!knownGenerics[typeElement];
|
|
34
37
|
typedefs.push(
|
|
35
|
-
`/** ${hasGeneric ?
|
|
38
|
+
`/** ${hasGeneric ? `@template ${knownGenerics[typeElement]} ` : ""}@typedef {import('${moduleSpecifier}').${typeElement}${hasGeneric ? `<${knownGenerics[typeElement]}>` : ""}} ${typeElement} */`
|
|
36
39
|
);
|
|
37
40
|
}
|
|
38
41
|
});
|
|
@@ -3,6 +3,7 @@ import { outputDebug } from '@shopify/cli-kit/node/output';
|
|
|
3
3
|
import { joinPath } from '@shopify/cli-kit/node/path';
|
|
4
4
|
import { getCodeFormatOptions, formatCode } from '../format-code.js';
|
|
5
5
|
import { transpileFile } from './file.js';
|
|
6
|
+
import { findFileWithExtension } from '../file.js';
|
|
6
7
|
|
|
7
8
|
const DEFAULT_JS_CONFIG = {
|
|
8
9
|
checkJs: false,
|
|
@@ -120,10 +121,13 @@ async function transpileProject(projectDir, keepTypes = true) {
|
|
|
120
121
|
);
|
|
121
122
|
}
|
|
122
123
|
try {
|
|
123
|
-
const
|
|
124
|
-
let eslintrc = await readFile(
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
const { filepath = joinPath(projectDir, ".eslintrc.cjs") } = await findFileWithExtension(projectDir, ".eslintrc", ["cjs", "js"]);
|
|
125
|
+
let eslintrc = await readFile(filepath);
|
|
126
|
+
if (!keepTypes) {
|
|
127
|
+
eslintrc = eslintrc.replace(/\/\*\*[\s*]+@type.+\s+\*\/\s?/gim, "");
|
|
128
|
+
}
|
|
129
|
+
eslintrc = eslintrc.replace(/\s*,?\s*['"`]plugin:hydrogen\/typescript['"`]/gim, "").replace(/\s+['"`]@typescript-eslint\/.+,/gim, "");
|
|
130
|
+
await writeFile(filepath, await formatCode(eslintrc, formatConfig));
|
|
127
131
|
} catch (error) {
|
|
128
132
|
outputDebug(
|
|
129
133
|
"Could not remove TS rules from .eslintrc:\n" + error.stack
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { fanoutHooks } from '@shopify/cli-kit/node/plugins';
|
|
2
|
+
import { outputDebug } from '@shopify/cli-kit/node/output';
|
|
3
|
+
import { BugError, AbortError } from '@shopify/cli-kit/node/error';
|
|
4
|
+
|
|
5
|
+
async function startTunnelPlugin(config, port, provider) {
|
|
6
|
+
const hooks = await fanoutHooks(config, "tunnel_start", { port, provider });
|
|
7
|
+
const results = Object.values(hooks).filter(
|
|
8
|
+
(tunnelResponse) => !tunnelResponse?.isErr() || tunnelResponse.error.type !== "invalid-provider"
|
|
9
|
+
);
|
|
10
|
+
const first = results[0];
|
|
11
|
+
if (!first)
|
|
12
|
+
throw new BugError(`We couldn't find the ${provider} tunnel plugin`);
|
|
13
|
+
if (first.isErr())
|
|
14
|
+
throw new AbortError(
|
|
15
|
+
`${provider} failed to start the tunnel.
|
|
16
|
+
${first.error.message}`
|
|
17
|
+
);
|
|
18
|
+
return first.value;
|
|
19
|
+
}
|
|
20
|
+
async function pollTunnelURL(tunnelClient) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
let retries = 0;
|
|
23
|
+
const pollTunnelStatus = async () => {
|
|
24
|
+
const result = tunnelClient.getTunnelStatus();
|
|
25
|
+
outputDebug(
|
|
26
|
+
`Polling tunnel status for ${tunnelClient.provider} (attempt ${retries}): ${result.status}`
|
|
27
|
+
);
|
|
28
|
+
if (result.status === "error")
|
|
29
|
+
return reject(new AbortError(result.message, result.tryMessage));
|
|
30
|
+
if (result.status === "connected") {
|
|
31
|
+
resolve(result.url);
|
|
32
|
+
} else {
|
|
33
|
+
retries += 1;
|
|
34
|
+
startPolling();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const startPolling = () => {
|
|
38
|
+
setTimeout(pollTunnelStatus, 500);
|
|
39
|
+
};
|
|
40
|
+
pollTunnelStatus();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { pollTunnelURL, startTunnelPlugin };
|
|
@@ -5,8 +5,8 @@ import { joinPath, relativePath } from '@shopify/cli-kit/node/path';
|
|
|
5
5
|
const VIRTUAL_ROUTES_DIR = "virtual-routes/routes";
|
|
6
6
|
const VIRTUAL_ROOT = "virtual-routes/virtual-root";
|
|
7
7
|
async function addVirtualRoutes(config) {
|
|
8
|
+
const distPath = process.env.SHOPIFY_UNIT_TEST ? fileURLToPath(new URL("../../../hydrogen/src/vite", import.meta.url)) : fileURLToPath(new URL("..", import.meta.url));
|
|
8
9
|
const userRouteList = Object.values(config.routes);
|
|
9
|
-
const distPath = fileURLToPath(new URL("..", import.meta.url));
|
|
10
10
|
const virtualRoutesPath = joinPath(distPath, VIRTUAL_ROUTES_DIR);
|
|
11
11
|
for (const absoluteFilePath of await glob(
|
|
12
12
|
joinPath(virtualRoutesPath, "**", "*")
|
package/dist/lib/vite-config.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { joinPath } from '@shopify/cli-kit/node/path';
|
|
1
|
+
import { joinPath, resolvePath, dirname, basename } from '@shopify/cli-kit/node/path';
|
|
2
|
+
import { findFileWithExtension } from './file.js';
|
|
2
3
|
|
|
3
|
-
async function
|
|
4
|
+
async function hasViteConfig(root) {
|
|
5
|
+
const result = await findFileWithExtension(root, "vite.config");
|
|
6
|
+
return !!result.filepath;
|
|
7
|
+
}
|
|
8
|
+
async function getViteConfig(root, ssrEntryFlag) {
|
|
4
9
|
const vite = await import('vite');
|
|
5
10
|
const command = "build";
|
|
6
11
|
const mode = process.env.NODE_ENV || "production";
|
|
@@ -18,13 +23,19 @@ async function getViteConfig(root) {
|
|
|
18
23
|
mode,
|
|
19
24
|
mode
|
|
20
25
|
);
|
|
26
|
+
const { appDirectory, serverBuildFile, routes } = getRemixConfigFromVite(resolvedViteConfig);
|
|
21
27
|
const serverOutDir = resolvedViteConfig.build.outDir;
|
|
22
28
|
const clientOutDir = serverOutDir.replace(/server$/, "client");
|
|
23
29
|
const rollupOutput = resolvedViteConfig.build.rollupOptions.output;
|
|
24
30
|
const { entryFileNames } = (Array.isArray(rollupOutput) ? rollupOutput[0] : rollupOutput) ?? {};
|
|
25
31
|
const serverOutFile = joinPath(
|
|
26
32
|
serverOutDir,
|
|
27
|
-
typeof entryFileNames === "string" ? entryFileNames : "index.js"
|
|
33
|
+
typeof entryFileNames === "string" ? entryFileNames : serverBuildFile ?? "index.js"
|
|
34
|
+
);
|
|
35
|
+
const ssrEntry = ssrEntryFlag ?? resolvedViteConfig.build.ssr;
|
|
36
|
+
const resolvedSsrEntry = resolvePath(
|
|
37
|
+
resolvedViteConfig.root,
|
|
38
|
+
typeof ssrEntry === "string" ? ssrEntry : "server"
|
|
28
39
|
);
|
|
29
40
|
return {
|
|
30
41
|
clientOutDir,
|
|
@@ -32,14 +43,33 @@ async function getViteConfig(root) {
|
|
|
32
43
|
serverOutFile,
|
|
33
44
|
resolvedViteConfig,
|
|
34
45
|
userViteConfig: maybeConfig.config,
|
|
35
|
-
remixConfig:
|
|
46
|
+
remixConfig: {
|
|
47
|
+
routes: routes ?? {},
|
|
48
|
+
appDirectory: appDirectory ?? joinPath(resolvedViteConfig.root, "app"),
|
|
49
|
+
rootDirectory: resolvedViteConfig.root,
|
|
50
|
+
serverEntryPoint: (await findFileWithExtension(
|
|
51
|
+
dirname(resolvedSsrEntry),
|
|
52
|
+
basename(resolvedSsrEntry)
|
|
53
|
+
)).filepath || resolvedSsrEntry
|
|
54
|
+
}
|
|
36
55
|
};
|
|
37
56
|
}
|
|
38
57
|
function getRemixConfigFromVite(viteConfig) {
|
|
39
|
-
const { remixConfig } = viteConfig
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
58
|
+
const { remixConfig } = findHydrogenPlugin(viteConfig)?.api?.getPluginOptions() ?? {};
|
|
59
|
+
return remixConfig ? {
|
|
60
|
+
appDirectory: remixConfig.appDirectory,
|
|
61
|
+
serverBuildFile: remixConfig.serverBuildFile,
|
|
62
|
+
routes: remixConfig.routes
|
|
63
|
+
} : {};
|
|
64
|
+
}
|
|
65
|
+
function findPlugin(config, name) {
|
|
66
|
+
return config.plugins.find((plugin) => plugin.name === name);
|
|
67
|
+
}
|
|
68
|
+
function findHydrogenPlugin(config) {
|
|
69
|
+
return findPlugin(config, "hydrogen:main");
|
|
70
|
+
}
|
|
71
|
+
function findOxygenPlugin(config) {
|
|
72
|
+
return findPlugin(config, "oxygen:main");
|
|
43
73
|
}
|
|
44
74
|
|
|
45
|
-
export { getViteConfig };
|
|
75
|
+
export { findHydrogenPlugin, findOxygenPlugin, getViteConfig, hasViteConfig };
|