@shopify/cli-hydrogen 8.0.4 → 8.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.
Files changed (162) hide show
  1. package/dist/{lib/setups/i18n/templates → assets/hydrogen/i18n}/domains.ts +1 -1
  2. package/dist/assets/hydrogen/i18n/mock-i18n-types.ts +3 -0
  3. package/dist/{lib/setups/i18n/templates → assets/hydrogen/i18n}/subdomains.ts +1 -1
  4. package/dist/{lib/setups/i18n/templates → assets/hydrogen/i18n}/subfolders.ts +1 -1
  5. package/dist/{generator-templates → assets/hydrogen}/starter/.eslintrc.cjs +1 -0
  6. package/dist/{generator-templates → assets/hydrogen}/starter/CHANGELOG.md +14 -0
  7. package/dist/assets/hydrogen/starter/app/components/Aside.tsx +76 -0
  8. package/dist/{generator-templates → assets/hydrogen}/starter/app/components/Cart.tsx +38 -14
  9. package/dist/{generator-templates → assets/hydrogen}/starter/app/components/Footer.tsx +30 -13
  10. package/dist/{generator-templates → assets/hydrogen}/starter/app/components/Header.tsx +52 -12
  11. package/dist/{generator-templates/starter/app/components/Layout.tsx → assets/hydrogen/starter/app/components/PageLayout.tsx} +38 -28
  12. package/dist/{generator-templates → assets/hydrogen}/starter/app/components/Search.tsx +5 -3
  13. package/dist/{generator-templates → assets/hydrogen}/starter/app/entry.server.tsx +8 -2
  14. package/dist/{generator-templates → assets/hydrogen}/starter/app/lib/fragments.ts +70 -0
  15. package/dist/assets/hydrogen/starter/app/root.tsx +204 -0
  16. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/_index.tsx +62 -25
  17. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account.addresses.tsx +0 -1
  18. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account.orders.$id.tsx +2 -2
  19. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account.profile.tsx +0 -1
  20. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/api.predictive-search.tsx +6 -1
  21. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +34 -8
  22. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/blogs.$blogHandle._index.tsx +36 -10
  23. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/blogs._index.tsx +35 -12
  24. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/cart.tsx +7 -7
  25. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/collections.$handle.tsx +49 -7
  26. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/collections._index.tsx +32 -6
  27. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/collections.all.tsx +31 -6
  28. package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +84 -0
  29. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/products.$handle.tsx +82 -17
  30. package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/search.tsx +4 -1
  31. package/dist/{generator-templates → assets/hydrogen}/starter/app/styles/app.css +22 -4
  32. package/dist/{generator-templates → assets/hydrogen}/starter/env.d.ts +1 -0
  33. package/dist/{generator-templates → assets/hydrogen}/starter/package.json +10 -10
  34. package/dist/{generator-templates → assets/hydrogen}/starter/storefrontapi.generated.d.ts +3 -1
  35. package/dist/{generator-templates → assets/hydrogen}/starter/vite.config.ts +15 -0
  36. package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/routes/index.jsx +0 -10
  37. package/dist/{generator-templates/assets → assets/hydrogen}/vite/vite.config.js +15 -0
  38. package/dist/commands/hydrogen/build.js +119 -36
  39. package/dist/commands/hydrogen/debug/cpu.js +74 -64
  40. package/dist/commands/hydrogen/deploy.js +4 -4
  41. package/dist/commands/hydrogen/dev.js +133 -51
  42. package/dist/{init.d.ts → commands/hydrogen/init.d.ts} +5 -5
  43. package/dist/commands/hydrogen/init.js +17 -8
  44. package/dist/commands/hydrogen/preview.js +101 -13
  45. package/dist/commands/hydrogen/setup/vite.js +2 -2
  46. package/dist/commands/hydrogen/setup.js +1 -1
  47. package/dist/commands/hydrogen/upgrade.js +53 -50
  48. package/dist/index.d.ts +403 -0
  49. package/dist/index.js +61 -0
  50. package/dist/lib/build.js +48 -37
  51. package/dist/lib/bundle/analyzer.js +2 -4
  52. package/dist/lib/check-version.js +38 -18
  53. package/dist/lib/classic-compiler/build.js +11 -4
  54. package/dist/lib/classic-compiler/debug-cpu.js +52 -0
  55. package/dist/lib/classic-compiler/dev.js +12 -5
  56. package/dist/lib/codegen.js +34 -9
  57. package/dist/lib/cpu-profiler.js +29 -12
  58. package/dist/lib/defer.js +13 -7
  59. package/dist/lib/deps-optimizer.js +146 -0
  60. package/dist/lib/flags.js +2 -7
  61. package/dist/lib/format-code.js +1 -2
  62. package/dist/lib/import-utils.js +21 -0
  63. package/dist/lib/live-reload.js +15 -5
  64. package/dist/lib/log.js +24 -2
  65. package/dist/lib/mini-oxygen/index.js +6 -2
  66. package/dist/lib/mini-oxygen/node.js +18 -4
  67. package/dist/lib/mini-oxygen/workerd.js +18 -5
  68. package/dist/lib/onboarding/local.js +1 -1
  69. package/dist/lib/onboarding/setup-template.mocks.js +7 -11
  70. package/dist/lib/remix-config.js +11 -9
  71. package/dist/lib/remix-version-check.js +8 -13
  72. package/dist/lib/resource-cleanup.js +13 -0
  73. package/dist/lib/setups/css/assets.js +3 -3
  74. package/dist/lib/setups/css/css-modules.js +2 -2
  75. package/dist/lib/setups/css/postcss.js +2 -2
  76. package/dist/lib/setups/css/tailwind.js +2 -2
  77. package/dist/lib/setups/css/vanilla-extract.js +2 -2
  78. package/dist/lib/setups/i18n/index.js +3 -5
  79. package/dist/lib/setups/routes/generate.js +17 -16
  80. package/dist/lib/template-diff.js +120 -42
  81. package/dist/lib/template-downloader.js +6 -11
  82. package/dist/lib/transpile/morph/typedefs.js +17 -0
  83. package/dist/lib/virtual-routes.js +2 -2
  84. package/dist/lib/vite-config.js +2 -1
  85. package/oclif.manifest.json +89 -1
  86. package/package.json +13 -9
  87. package/dist/generator-templates/starter/app/components/Aside.tsx +0 -47
  88. package/dist/generator-templates/starter/app/lib/root-data.ts +0 -11
  89. package/dist/generator-templates/starter/app/root.tsx +0 -227
  90. package/dist/generator-templates/starter/app/routes/pages.$handle.tsx +0 -56
  91. package/dist/lib/setups/i18n/mock-i18n-types.js +0 -1
  92. package/dist/lib/setups/i18n/templates/domains.js +0 -14
  93. package/dist/lib/setups/i18n/templates/subdomains.js +0 -14
  94. package/dist/lib/setups/i18n/templates/subfolders.js +0 -13
  95. package/dist/lib/setups/routes/templates/locale-check.js +0 -9
  96. package/dist/virtual-routes/components/IconDiscord.jsx +0 -21
  97. /package/dist/{lib/bundle/bundle-analyzer.html → assets/hydrogen/bundle/analyzer.html} +0 -0
  98. /package/dist/{generator-templates/assets → assets/hydrogen}/css-modules/package.json +0 -0
  99. /package/dist/{generator-templates/assets → assets/hydrogen}/postcss/package.json +0 -0
  100. /package/dist/{generator-templates/assets → assets/hydrogen}/postcss/postcss.config.js +0 -0
  101. /package/dist/{lib/setups/routes/templates → assets/hydrogen/routes}/locale-check.ts +0 -0
  102. /package/dist/{generator-templates → assets/hydrogen}/starter/.eslintignore +0 -0
  103. /package/dist/{generator-templates → assets/hydrogen}/starter/.graphqlrc.yml +0 -0
  104. /package/dist/{generator-templates → assets/hydrogen}/starter/README.md +0 -0
  105. /package/dist/{generator-templates → assets/hydrogen}/starter/app/assets/favicon.svg +0 -0
  106. /package/dist/{generator-templates → assets/hydrogen}/starter/app/entry.client.tsx +0 -0
  107. /package/dist/{generator-templates → assets/hydrogen}/starter/app/graphql/customer-account/CustomerAddressMutations.ts +0 -0
  108. /package/dist/{generator-templates → assets/hydrogen}/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +0 -0
  109. /package/dist/{generator-templates → assets/hydrogen}/starter/app/graphql/customer-account/CustomerOrderQuery.ts +0 -0
  110. /package/dist/{generator-templates → assets/hydrogen}/starter/app/graphql/customer-account/CustomerOrdersQuery.ts +0 -0
  111. /package/dist/{generator-templates → assets/hydrogen}/starter/app/graphql/customer-account/CustomerUpdateMutation.ts +0 -0
  112. /package/dist/{generator-templates → assets/hydrogen}/starter/app/lib/search.ts +0 -0
  113. /package/dist/{generator-templates → assets/hydrogen}/starter/app/lib/session.ts +0 -0
  114. /package/dist/{generator-templates → assets/hydrogen}/starter/app/lib/variants.ts +0 -0
  115. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/$.tsx +0 -0
  116. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/[robots.txt].tsx +0 -0
  117. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/[sitemap.xml].tsx +0 -0
  118. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account.$.tsx +0 -0
  119. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account._index.tsx +0 -0
  120. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account.orders._index.tsx +0 -0
  121. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account.tsx +0 -0
  122. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account_.authorize.tsx +0 -0
  123. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account_.login.tsx +0 -0
  124. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/account_.logout.tsx +0 -0
  125. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/cart.$lines.tsx +0 -0
  126. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/discount.$code.tsx +0 -0
  127. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/policies.$handle.tsx +0 -0
  128. /package/dist/{generator-templates → assets/hydrogen}/starter/app/routes/policies._index.tsx +0 -0
  129. /package/dist/{generator-templates → assets/hydrogen}/starter/app/styles/reset.css +0 -0
  130. /package/dist/{generator-templates → assets/hydrogen}/starter/customer-accountapi.generated.d.ts +0 -0
  131. /package/dist/{generator-templates → assets/hydrogen}/starter/public/.gitkeep +0 -0
  132. /package/dist/{generator-templates → assets/hydrogen}/starter/server.ts +0 -0
  133. /package/dist/{generator-templates → assets/hydrogen}/starter/tsconfig.json +0 -0
  134. /package/dist/{generator-templates/assets → assets/hydrogen}/tailwind/package.json +0 -0
  135. /package/dist/{generator-templates/assets → assets/hydrogen}/tailwind/postcss.config.js +0 -0
  136. /package/dist/{generator-templates/assets → assets/hydrogen}/tailwind/tailwind.config.js +0 -0
  137. /package/dist/{generator-templates/assets → assets/hydrogen}/tailwind/tailwind.css +0 -0
  138. /package/dist/{generator-templates/assets → assets/hydrogen}/vanilla-extract/package.json +0 -0
  139. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/assets/debug-network.css +0 -0
  140. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/assets/favicon-dark.svg +0 -0
  141. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/assets/favicon.svg +0 -0
  142. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/assets/inter-variable-font.woff2 +0 -0
  143. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/assets/jetbrainsmono-variable-font.woff2 +0 -0
  144. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/assets/styles.css +0 -0
  145. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/FlameChartWrapper.jsx +0 -0
  146. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/HydrogenLogoBaseBW.jsx +0 -0
  147. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/HydrogenLogoBaseColor.jsx +0 -0
  148. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/IconBanner.jsx +0 -0
  149. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/IconClose.jsx +0 -0
  150. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/IconDiscard.jsx +0 -0
  151. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/IconError.jsx +0 -0
  152. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/IconGithub.jsx +0 -0
  153. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/IconTwitter.jsx +0 -0
  154. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/Layout.jsx +0 -0
  155. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/RequestDetails.jsx +0 -0
  156. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/RequestTable.jsx +0 -0
  157. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/components/RequestWaterfall.jsx +0 -0
  158. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/lib/useDebugNetworkServer.jsx +0 -0
  159. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/routes/graphiql.jsx +0 -0
  160. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/routes/subrequest-profiler.jsx +0 -0
  161. /package/dist/{virtual-routes → assets/hydrogen/virtual-routes}/virtual-root.jsx +0 -0
  162. /package/dist/{generator-templates/assets → assets/hydrogen}/vite/package.json +0 -0
@@ -0,0 +1,146 @@
1
+ import { BugError, AbortError } from '@shopify/cli-kit/node/error';
2
+ import { extname } from '@shopify/cli-kit/node/path';
3
+ import { renderFatalError } from '@shopify/cli-kit/node/ui';
4
+ import colors from '@shopify/cli-kit/node/colors';
5
+ import { importLangAstGrep } from './ast.js';
6
+ import { replaceFileContent } from './file.js';
7
+ import { outputInfo } from '@shopify/cli-kit/node/output';
8
+
9
+ const throttledOptimizableDeps = /* @__PURE__ */ new Set();
10
+ let debouncedBannerTimeout;
11
+ function createEntryPointErrorHandler({
12
+ disableDepsOptimizer,
13
+ showSuccessBanner,
14
+ configFile,
15
+ formatOptionsPromise
16
+ }) {
17
+ return async function entryPointErrorHandler({
18
+ optimizableDependency,
19
+ stack
20
+ }) {
21
+ const message = stack.split("\n")[0] ?? stack;
22
+ const cleanStack = stack.split("\n").filter((line) => !line.includes("virtual:remix")).join("\n");
23
+ const headline = "MiniOxygen encountered an error while running your app's entry point";
24
+ if (optimizableDependency) {
25
+ if (disableDepsOptimizer || !configFile) {
26
+ const depError = new BugError(
27
+ `${headline}:
28
+
29
+ ${colors.dim(message)}`,
30
+ `Try adding '${colors.yellow(
31
+ optimizableDependency
32
+ )}' to your Vite config in ssr.optimizeDeps.include`
33
+ );
34
+ depError.stack = cleanStack;
35
+ renderFatalError(depError);
36
+ } else if (!throttledOptimizableDeps.has(optimizableDependency)) {
37
+ throttledOptimizableDeps.add(optimizableDependency);
38
+ setTimeout(
39
+ () => throttledOptimizableDeps.delete(optimizableDependency),
40
+ 2e3
41
+ );
42
+ addToViteOptimizeDeps(
43
+ optimizableDependency,
44
+ configFile,
45
+ await formatOptionsPromise,
46
+ cleanStack
47
+ ).then(() => {
48
+ setTimeout(() => {
49
+ outputInfo(
50
+ `
51
+ Added '${colors.yellow(
52
+ optimizableDependency
53
+ )}' to your Vite config in ssr.optimizeDeps.include
54
+ `
55
+ );
56
+ }, 200);
57
+ clearTimeout(debouncedBannerTimeout);
58
+ debouncedBannerTimeout = setTimeout(showSuccessBanner, 2e3);
59
+ }).catch((error) => {
60
+ clearTimeout(debouncedBannerTimeout);
61
+ renderFatalError(error);
62
+ });
63
+ }
64
+ } else {
65
+ const unknownError = new BugError(
66
+ headline + ":\n\n" + colors.dim(message)
67
+ );
68
+ unknownError.stack = cleanStack;
69
+ renderFatalError(unknownError);
70
+ }
71
+ };
72
+ }
73
+ const ssrOptimizeDepsIncludeRule = {
74
+ rule: {
75
+ pattern: "[$$$]",
76
+ inside: {
77
+ kind: "pair",
78
+ stopBy: "end",
79
+ has: {
80
+ field: "key",
81
+ regex: "include",
82
+ stopBy: "end"
83
+ },
84
+ inside: {
85
+ kind: "pair",
86
+ stopBy: "end",
87
+ has: {
88
+ field: "key",
89
+ regex: "optimizeDeps",
90
+ stopBy: "end"
91
+ },
92
+ inside: {
93
+ kind: "pair",
94
+ stopBy: "end",
95
+ has: {
96
+ field: "key",
97
+ regex: "ssr",
98
+ stopBy: "end"
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ };
105
+ async function addToViteOptimizeDeps(dependency, configFile, formatOptions, errorStack) {
106
+ const ext = extname(configFile).replace(/^\.m?/, "");
107
+ const astGrep = await importLangAstGrep(ext);
108
+ await replaceFileContent(configFile, formatOptions, (content) => {
109
+ const root = astGrep.parse(content).root();
110
+ const node = root.find(ssrOptimizeDepsIncludeRule);
111
+ if (!node) {
112
+ throw new AbortError(
113
+ `The dependency '${colors.yellow(
114
+ dependency
115
+ )}' needs to be optimized by Vite, but couldn't be added to the Vite config.`,
116
+ `Add the following code manually to your Vite config:
117
+
118
+ ` + colors.yellow(`ssr: {optimizeDeps: {include: ['${dependency}']}}`)
119
+ );
120
+ }
121
+ const isAlreadyAdded = !!node.find({
122
+ rule: {
123
+ kind: "string_fragment",
124
+ regex: `^${dependency}$`
125
+ }
126
+ });
127
+ if (isAlreadyAdded) {
128
+ const error = new BugError(
129
+ `A dependency related to '${colors.yellow(
130
+ dependency
131
+ )}' might need to be optimized by Vite but couldn't be configured automatically:
132
+
133
+ ${colors.dim(
134
+ errorStack.split("\n")[0]
135
+ )}`,
136
+ `If your app doesn't load, check the following stack trace and try fixing the problem by adding the imported dependency to the \`ssr.optimizeDeps.include\` array in your Vite config file.`
137
+ );
138
+ error.stack = errorStack;
139
+ throw error;
140
+ }
141
+ const { start } = node.range();
142
+ return content.slice(0, start.index + 1) + `'${dependency}',` + content.slice(start.index + 1);
143
+ });
144
+ }
145
+
146
+ export { addToViteOptimizeDeps, createEntryPointErrorHandler };
package/dist/lib/flags.js CHANGED
@@ -78,8 +78,7 @@ const commonFlags = {
78
78
  codegen: {
79
79
  codegen: Flags.boolean({
80
80
  description: "Automatically generates GraphQL types for your project\u2019s Storefront API queries.",
81
- required: false,
82
- default: false
81
+ required: false
83
82
  }),
84
83
  "codegen-config-path": Flags.string({
85
84
  description: "Specifies a path to a codegen configuration file. Defaults to `<root>/codegen.ts` if this file exists.",
@@ -106,8 +105,7 @@ const commonFlags = {
106
105
  debug: {
107
106
  debug: Flags.boolean({
108
107
  description: "Enables inspector connections to the server with a debugger such as Visual Studio Code or Chrome DevTools.",
109
- env: "SHOPIFY_HYDROGEN_FLAG_DEBUG",
110
- default: false
108
+ env: "SHOPIFY_HYDROGEN_FLAG_DEBUG"
111
109
  })
112
110
  },
113
111
  inspectorPort: {
@@ -119,7 +117,6 @@ const commonFlags = {
119
117
  diff: {
120
118
  diff: Flags.boolean({
121
119
  description: "Applies the current files on top of Hydrogen's starter template in a temporary directory.",
122
- default: false,
123
120
  required: false,
124
121
  hidden: true
125
122
  })
@@ -149,7 +146,6 @@ const commonFlags = {
149
146
  hidden: true,
150
147
  description: "Use tunneling for local development and push the tunneling domain to admin. Required to use Customer Account API's Oauth flow",
151
148
  required: false,
152
- default: false,
153
149
  env: "SHOPIFY_HYDROGEN_FLAG_CUSTOMER_ACCOUNT_PUSH"
154
150
  })
155
151
  },
@@ -157,7 +153,6 @@ const commonFlags = {
157
153
  verbose: Flags.boolean({
158
154
  description: "Outputs more information about the command's execution.",
159
155
  required: false,
160
- default: false,
161
156
  env: "SHOPIFY_HYDROGEN_FLAG_VERBOSE"
162
157
  })
163
158
  }
@@ -1,4 +1,5 @@
1
1
  import { extname } from '@shopify/cli-kit/node/path';
2
+ import * as prettier from 'prettier';
2
3
 
3
4
  const DEFAULT_PRETTIER_CONFIG = {
4
5
  arrowParens: "always",
@@ -8,7 +9,6 @@ const DEFAULT_PRETTIER_CONFIG = {
8
9
  };
9
10
  async function getCodeFormatOptions(filePath = process.cwd()) {
10
11
  try {
11
- const prettier = await import('prettier');
12
12
  return await prettier.resolveConfig(filePath) || DEFAULT_PRETTIER_CONFIG;
13
13
  } catch {
14
14
  return DEFAULT_PRETTIER_CONFIG;
@@ -16,7 +16,6 @@ async function getCodeFormatOptions(filePath = process.cwd()) {
16
16
  }
17
17
  async function formatCode(content, config = DEFAULT_PRETTIER_CONFIG, filePath = "") {
18
18
  const ext = extname(filePath);
19
- const prettier = await import('prettier');
20
19
  return prettier.format(content, {
21
20
  // Specify the TypeScript parser for ts/tsx files. Otherwise
22
21
  // we need to use the babel parser because the default parser
@@ -0,0 +1,21 @@
1
+ import { createRequire } from 'node:module';
2
+ import { findUpAndReadPackageJson } from '@shopify/cli-kit/node/node-package-manager';
3
+ import { joinPath, dirname } from '@shopify/cli-kit/node/path';
4
+
5
+ const require2 = createRequire(import.meta.url);
6
+ async function importVite(root) {
7
+ const vitePath = require2.resolve("vite", { paths: [root] });
8
+ const vitePackageJson = await findUpAndReadPackageJson(vitePath);
9
+ const viteNodeIndexFile = vitePackageJson.content.exports?.["."].import.default;
10
+ const viteNodePath = joinPath(
11
+ dirname(vitePackageJson.path),
12
+ viteNodeIndexFile
13
+ );
14
+ return import(viteNodePath);
15
+ }
16
+ function importLocal(packageName, path) {
17
+ const realPath = require2.resolve(packageName, { paths: [path] });
18
+ return import(realPath);
19
+ }
20
+
21
+ export { importLocal, importVite };
@@ -1,13 +1,23 @@
1
1
  import http from 'node:http';
2
2
  import { handleRemixImportFail } from './remix-config.js';
3
+ import { importLocal } from './import-utils.js';
3
4
 
4
- async function setupLiveReload(devServerPort) {
5
+ async function setupLiveReload(devServerPort, root) {
5
6
  try {
6
7
  const [{ updates: hmrUpdates }, { serve }, { detectLoaderChanges }, { ok, err }] = await Promise.all([
7
- import('@remix-run/dev/dist/devServer_unstable/hmr.js'),
8
- import('@remix-run/dev/dist/devServer_unstable/socket.js'),
9
- import('@remix-run/dev/dist/devServer_unstable/hdr.js'),
10
- import('@remix-run/dev/dist/result.js')
8
+ importLocal(
9
+ "@remix-run/dev/dist/devServer_unstable/hmr.js",
10
+ root
11
+ ),
12
+ importLocal(
13
+ "@remix-run/dev/dist/devServer_unstable/socket.js",
14
+ root
15
+ ),
16
+ importLocal(
17
+ "@remix-run/dev/dist/devServer_unstable/hdr.js",
18
+ root
19
+ ),
20
+ importLocal("@remix-run/dev/dist/result.js", root)
11
21
  ]).catch(handleRemixImportFail);
12
22
  const state = {};
13
23
  const server = http.createServer(function(req, res) {
package/dist/lib/log.js CHANGED
@@ -3,6 +3,7 @@ import { BugError } from '@shopify/cli-kit/node/error';
3
3
  import { outputContent, outputToken } from '@shopify/cli-kit/node/output';
4
4
  import colors from '@shopify/cli-kit/node/colors';
5
5
  import { getGraphiQLUrl } from './graphiql-url.js';
6
+ import { importLocal } from './import-utils.js';
6
7
 
7
8
  const originalConsole = { ...console };
8
9
  const methodsReplaced = /* @__PURE__ */ new Set();
@@ -153,6 +154,12 @@ function muteDevLogs({ workerReload } = {}) {
153
154
  () => {
154
155
  }
155
156
  ],
157
+ [
158
+ // This log must come from Rollup and does not go through Vite's customLogger
159
+ ([first]) => typeof first === "string" && /^Generated an empty chunk:/i.test(first),
160
+ () => {
161
+ }
162
+ ],
156
163
  [
157
164
  // Log new lines between Request logs and other logs
158
165
  ([first], existingMatches) => {
@@ -172,6 +179,18 @@ function muteDevLogs({ workerReload } = {}) {
172
179
  (params) => params
173
180
  ]
174
181
  );
182
+ const processStderrWrite = process.stderr.write;
183
+ const timeout = setTimeout(() => {
184
+ process.stderr.write = processStderrWrite;
185
+ }, 5e3);
186
+ process.stderr.write = (...args) => {
187
+ if (typeof args[0] === "string" && args[0].includes("Could not find ts-node")) {
188
+ clearTimeout(timeout);
189
+ process.stderr.write = processStderrWrite;
190
+ return false;
191
+ }
192
+ return processStderrWrite.apply(process.stderr, args);
193
+ };
175
194
  }
176
195
  const originalWrite = process.stdout.write;
177
196
  function muteAuthLogs({
@@ -353,9 +372,12 @@ function createRemixLogger() {
353
372
  }
354
373
  };
355
374
  }
356
- async function muteRemixLogs() {
375
+ async function muteRemixLogs(root) {
357
376
  try {
358
- const { logger } = await import('@remix-run/dev/dist/tux/logger.js');
377
+ const { logger } = await importLocal(
378
+ "@remix-run/dev/dist/tux/logger.js",
379
+ root
380
+ );
359
381
  logger.warn = logger.debug = logger.info = () => {
360
382
  };
361
383
  } catch {
@@ -1,8 +1,12 @@
1
+ import { importLocal } from '../import-utils.js';
1
2
  import { handleMiniOxygenImportFail } from './common.js';
2
3
  export { DEFAULT_INSPECTOR_PORT } from './common.js';
3
4
 
4
- async function buildAssetsUrl(port) {
5
- const { buildAssetsUrl: _buildAssetsUrl } = await import('@shopify/mini-oxygen').catch(handleMiniOxygenImportFail);
5
+ async function buildAssetsUrl(port, root) {
6
+ const { buildAssetsUrl: _buildAssetsUrl } = await importLocal(
7
+ "@shopify/mini-oxygen",
8
+ root
9
+ ).catch(handleMiniOxygenImportFail);
6
10
  return _buildAssetsUrl(port);
7
11
  }
8
12
  async function startMiniOxygen(options, useNodeRuntime = false) {
@@ -2,12 +2,14 @@ import { AsyncLocalStorage } from 'node:async_hooks';
2
2
  import { readFile } from '@shopify/cli-kit/node/fs';
3
3
  import { renderSuccess } from '@shopify/cli-kit/node/ui';
4
4
  import colors from '@shopify/cli-kit/node/colors';
5
+ import { AbortError } from '@shopify/cli-kit/node/error';
5
6
  import { DEFAULT_INSPECTOR_PORT } from '../flags.js';
6
7
  import { handleMiniOxygenImportFail, SUBREQUEST_PROFILER_ENDPOINT, logRequestLine } from './common.js';
7
8
  import { setConstructors, createLogRequestEvent, handleDebugNetworkRequest, H2O_BINDING_NAME } from '../request-events.js';
8
9
  import { findPort } from '../find-port.js';
9
10
  import { getUtilityBannerlines } from '../dev-shared.js';
10
11
  import { outputNewline } from '@shopify/cli-kit/node/output';
12
+ import { importLocal } from '../import-utils.js';
11
13
 
12
14
  async function startNodeServer({
13
15
  appPort,
@@ -16,9 +18,13 @@ async function startNodeServer({
16
18
  buildPathClient,
17
19
  env,
18
20
  debug = false,
19
- inspectorPort
21
+ inspectorPort,
22
+ root
20
23
  }) {
21
- const { startServer, Request, Response } = await import('@shopify/mini-oxygen/node').catch(handleMiniOxygenImportFail);
24
+ const { startServer, Request, Response } = await importLocal(
25
+ "@shopify/mini-oxygen/node",
26
+ root
27
+ ).catch(handleMiniOxygenImportFail);
22
28
  setConstructors({ Response });
23
29
  const logRequestEvent = createLogRequestEvent();
24
30
  const asyncLocalStorage = new AsyncLocalStorage();
@@ -40,8 +46,16 @@ async function startNodeServer({
40
46
  inspectorPort = await findPort(DEFAULT_INSPECTOR_PORT);
41
47
  (await import('node:inspector')).open(inspectorPort);
42
48
  }
49
+ const readWorkerFile = () => readFile(buildPathWorkerFile).catch((error) => {
50
+ throw new AbortError(
51
+ `Could not read worker file.
52
+
53
+ ` + error.stack,
54
+ "Did you build the project?"
55
+ );
56
+ });
43
57
  const miniOxygen = await startServer({
44
- script: await readFile(buildPathWorkerFile),
58
+ script: await readWorkerFile(),
45
59
  workerFile: buildPathWorkerFile,
46
60
  assetsDir: buildPathClient,
47
61
  publicPath: "",
@@ -100,7 +114,7 @@ async function startNodeServer({
100
114
  ...process.env
101
115
  };
102
116
  }
103
- nextOptions.script = await readFile(buildPathWorkerFile);
117
+ nextOptions.script = await readWorkerFile();
104
118
  await miniOxygen.reload(nextOptions);
105
119
  },
106
120
  showBanner(options) {
@@ -1,12 +1,14 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import { resolvePath, dirname } from '@shopify/cli-kit/node/path';
3
- import { readFile, createFileReadStream } from '@shopify/cli-kit/node/fs';
3
+ import { createFileReadStream, readFile } from '@shopify/cli-kit/node/fs';
4
4
  import { renderSuccess } from '@shopify/cli-kit/node/ui';
5
5
  import { outputNewline } from '@shopify/cli-kit/node/output';
6
+ import { AbortError } from '@shopify/cli-kit/node/error';
6
7
  import colors from '@shopify/cli-kit/node/colors';
7
8
  import { handleMiniOxygenImportFail, logRequestLine, SUBREQUEST_PROFILER_ENDPOINT } from './common.js';
8
9
  import { TUNNEL_DOMAIN, getUtilityBannerlines, getDebugBannerLine } from '../dev-shared.js';
9
10
  import { setConstructors, handleDebugNetworkRequest, H2O_BINDING_NAME, createLogRequestEvent } from '../request-events.js';
11
+ import { importLocal } from '../import-utils.js';
10
12
 
11
13
  async function startWorkerdServer({
12
14
  root,
@@ -19,7 +21,10 @@ async function startWorkerdServer({
19
21
  buildPathClient,
20
22
  env
21
23
  }) {
22
- const { createMiniOxygen, Response } = await import('@shopify/mini-oxygen').catch(handleMiniOxygenImportFail);
24
+ const { createMiniOxygen, Response } = await importLocal(
25
+ "@shopify/mini-oxygen",
26
+ root
27
+ ).catch(handleMiniOxygenImportFail);
23
28
  setConstructors({ Response });
24
29
  async function handleCustomerAccountSchema() {
25
30
  const require2 = createRequire(import.meta.url);
@@ -30,8 +35,16 @@ async function startWorkerdServer({
30
35
  headers: { "Content-Type": "application/json" }
31
36
  });
32
37
  }
33
- const absoluteBundlePath = resolvePath(root, buildPathWorkerFile);
34
38
  const mainWorkerName = "hydrogen";
39
+ const absoluteBundlePath = resolvePath(root, buildPathWorkerFile);
40
+ const readWorkerFile = () => readFile(absoluteBundlePath).catch((error) => {
41
+ throw new AbortError(
42
+ `Could not read worker file.
43
+
44
+ ` + error.stack,
45
+ "Did you build the project?"
46
+ );
47
+ });
35
48
  const miniOxygen = createMiniOxygen({
36
49
  debug,
37
50
  port: appPort,
@@ -74,7 +87,7 @@ async function startWorkerdServer({
74
87
  {
75
88
  type: "ESModule",
76
89
  path: absoluteBundlePath,
77
- contents: await readFile(absoluteBundlePath)
90
+ contents: await readWorkerFile()
78
91
  }
79
92
  ],
80
93
  bindings: { ...env },
@@ -94,7 +107,7 @@ async function startWorkerdServer({
94
107
  return miniOxygen.reload(async ({ workers }) => {
95
108
  const mainWorker = workers.find(({ name }) => name === mainWorkerName);
96
109
  if (Array.isArray(mainWorker.modules) && mainWorker.modules[0]) {
97
- mainWorker.modules[0].contents = await readFile(absoluteBundlePath);
110
+ mainWorker.modules[0].contents = await readWorkerFile();
98
111
  }
99
112
  if (nextOptions) {
100
113
  mainWorker.bindings = { ...nextOptions?.env ?? env };
@@ -42,7 +42,7 @@ async function setupLocalStarterTemplate(options, controller) {
42
42
  await waitForJob(storefrontInfo.session, jobId);
43
43
  return storefront;
44
44
  }).catch(abort);
45
- const templateDir = getStarterDir();
45
+ const templateDir = await getStarterDir();
46
46
  let backgroundWorkPromise = copy(
47
47
  templateDir,
48
48
  project.directory,
@@ -1,25 +1,21 @@
1
- import { fileURLToPath } from 'node:url';
2
1
  import { vi } from 'vitest';
3
2
  import { remove, createSymlink } from 'fs-extra/esm';
4
3
  import { writeFile } from '@shopify/cli-kit/node/fs';
5
- import { joinPath } from '@shopify/cli-kit/node/path';
6
- import { getRepoNodeModules } from '../build.js';
4
+ import { dirname, joinPath } from '@shopify/cli-kit/node/path';
5
+ import { getSkeletonSourceDir, getRepoNodeModules } from '../build.js';
7
6
 
8
7
  const { renderTasksHook } = vi.hoisted(() => ({ renderTasksHook: vi.fn() }));
9
8
  vi.mock("../template-downloader.js", async () => ({
10
9
  downloadMonorepoTemplates: () => Promise.resolve({
11
10
  version: "",
12
- templatesDir: fileURLToPath(
13
- new URL("../../../../../templates", import.meta.url)
14
- ),
15
- examplesDir: fileURLToPath(
16
- new URL("../../../../../examples", import.meta.url)
11
+ templatesDir: dirname(getSkeletonSourceDir()),
12
+ examplesDir: dirname(getSkeletonSourceDir()).replace(
13
+ "templates",
14
+ "examples"
17
15
  )
18
16
  }),
19
17
  downloadExternalRepo: () => Promise.resolve({
20
- templateDir: fileURLToPath(
21
- new URL("../../../../../templates/skeleton", import.meta.url)
22
- )
18
+ templateDir: getSkeletonSourceDir()
23
19
  })
24
20
  }));
25
21
  vi.mock("@shopify/cli-kit/node/ui", async () => {
@@ -1,14 +1,15 @@
1
1
  import { createRequire } from 'node:module';
2
- import { fileURLToPath } from 'node:url';
3
2
  import path from 'node:path';
4
3
  import { readdir } from 'node:fs/promises';
5
4
  import { AbortError } from '@shopify/cli-kit/node/error';
6
5
  import { outputWarn } from '@shopify/cli-kit/node/output';
7
6
  import { fileExists } from '@shopify/cli-kit/node/fs';
8
7
  import { muteRemixLogs } from './log.js';
9
- import { getRequiredRemixVersion } from './remix-version-check.js';
8
+ import { REQUIRED_REMIX_VERSION } from './remix-version-check.js';
10
9
  import { findFileWithExtension } from './file.js';
11
10
  import { getViteConfig } from './vite-config.js';
11
+ import { importLocal } from './import-utils.js';
12
+ import { isHydrogenMonorepo, hydrogenPackagesPath } from './build.js';
12
13
 
13
14
  async function hasRemixConfigFile(root) {
14
15
  const result = await findFileWithExtension(root, "remix.config");
@@ -33,7 +34,7 @@ function getProjectPaths(appPath) {
33
34
  };
34
35
  }
35
36
  function handleRemixImportFail() {
36
- const remixVersion = getRequiredRemixVersion();
37
+ const remixVersion = REQUIRED_REMIX_VERSION;
37
38
  throw new AbortError(
38
39
  "Could not load Remix packages.",
39
40
  `Please make sure you have \`@remix-run/dev@${remixVersion}\` installed and all the other Remix packages have the same version.`
@@ -50,13 +51,14 @@ async function getRemixConfig(root, mode = process.env.NODE_ENV) {
50
51
  if (!await hasRemixConfigFile(root)) {
51
52
  return (await getViteConfig(root)).remixConfig;
52
53
  }
53
- await muteRemixLogs();
54
- const { readConfig } = await import('@remix-run/dev/dist/config.js').catch(
55
- handleRemixImportFail
56
- );
54
+ await muteRemixLogs(root);
55
+ const { readConfig } = await importLocal(
56
+ "@remix-run/dev/dist/config.js",
57
+ root
58
+ ).catch(handleRemixImportFail);
57
59
  const config = await readConfig(root, mode);
58
- if (process.env.LOCAL_DEV) {
59
- const packagesPath = fileURLToPath(new URL("../../..", import.meta.url));
60
+ if (isHydrogenMonorepo && hydrogenPackagesPath) {
61
+ const packagesPath = hydrogenPackagesPath;
60
62
  config.watchPaths ??= [];
61
63
  config.watchPaths.push(
62
64
  ...(await readdir(packagesPath)).map(
@@ -1,16 +1,9 @@
1
1
  import { createRequire } from 'node:module';
2
- import { fileURLToPath } from 'node:url';
3
2
  import { renderWarning } from '@shopify/cli-kit/node/ui';
4
3
 
5
- function getRequiredRemixVersion(require2 = createRequire(import.meta.url)) {
6
- const hydrogenPkgJson = require2(fileURLToPath(
7
- new URL("../../package.json", import.meta.url)
8
- ));
9
- return hydrogenPkgJson.peerDependencies["@remix-run/dev"];
10
- }
11
- function checkRemixVersions() {
4
+ const REQUIRED_REMIX_VERSION = "^2.1.0";
5
+ function checkRemixVersions(projectPath, requiredVersionInHydrogen = REQUIRED_REMIX_VERSION) {
12
6
  const require2 = createRequire(import.meta.url);
13
- const requiredVersionInHydrogen = getRequiredRemixVersion(require2);
14
7
  const satisfiesSemver = require2("semver/functions/satisfies.js");
15
8
  const pkgs = [
16
9
  "dev",
@@ -20,7 +13,7 @@ function checkRemixVersions() {
20
13
  "node",
21
14
  "express",
22
15
  "eslint-config"
23
- ].map((name) => getRemixPackageVersion(require2, name));
16
+ ].map((name) => getRemixPackageVersion(require2, name, projectPath));
24
17
  const outOfSyncPkgs = pkgs.filter(
25
18
  (pkg) => pkg.version && !satisfiesSemver(pkg.version, requiredVersionInHydrogen)
26
19
  );
@@ -40,11 +33,13 @@ function checkRemixVersions() {
40
33
  ]
41
34
  });
42
35
  }
43
- function getRemixPackageVersion(require2, name) {
36
+ function getRemixPackageVersion(require2, name, root) {
44
37
  const pkgName = "@remix-run/" + name;
45
38
  const result = { name: pkgName, version: "" };
46
39
  try {
47
- const pkgJsonPath = require2.resolve(`${pkgName}/package.json`);
40
+ const pkgJsonPath = require2.resolve(`${pkgName}/package.json`, {
41
+ paths: [root]
42
+ });
48
43
  const pkgJson = require2(pkgJsonPath);
49
44
  result.version = pkgJson.version;
50
45
  } catch {
@@ -52,4 +47,4 @@ function getRemixPackageVersion(require2, name) {
52
47
  return result;
53
48
  }
54
49
 
55
- export { checkRemixVersions, getRequiredRemixVersion };
50
+ export { REQUIRED_REMIX_VERSION, checkRemixVersions };
@@ -0,0 +1,13 @@
1
+ function setupResourceCleanup(cleanup) {
2
+ let closingPromise;
3
+ const processExit = process.exit;
4
+ process.exit = async (code) => {
5
+ closingPromise ??= cleanup();
6
+ const timeout = setTimeout(() => processExit(code), 5e3);
7
+ await closingPromise;
8
+ clearTimeout(timeout);
9
+ return processExit(code);
10
+ };
11
+ }
12
+
13
+ export { setupResourceCleanup };
@@ -1,7 +1,7 @@
1
1
  import { readFile, writeFile, fileExists } from '@shopify/cli-kit/node/fs';
2
2
  import { joinPath } from '@shopify/cli-kit/node/path';
3
3
  import { renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
4
- import { getAssetDir } from '../../build.js';
4
+ import { getAssetsDir } from '../../build.js';
5
5
 
6
6
  const SETUP_CSS_STRATEGIES = [
7
7
  "tailwind",
@@ -9,8 +9,8 @@ const SETUP_CSS_STRATEGIES = [
9
9
  "vanilla-extract",
10
10
  "postcss"
11
11
  ];
12
- function copyAssets(feature, assets, rootDirectory, replacer = (content, filename) => content) {
13
- const setupAssetsPath = getAssetDir(feature);
12
+ async function copyAssets(feature, assets, rootDirectory, replacer = (content, filename) => content) {
13
+ const setupAssetsPath = await getAssetsDir(feature);
14
14
  return Promise.all(
15
15
  Object.entries(assets).map(async ([source, destination]) => {
16
16
  const content = await readFile(joinPath(setupAssetsPath, source));
@@ -1,14 +1,14 @@
1
1
  import { mergePackageJson } from '../../file.js';
2
2
  import { getCodeFormatOptions } from '../../format-code.js';
3
3
  import { injectCssBundlingLink } from './replacers.js';
4
- import { getAssetDir } from '../../build.js';
4
+ import { getAssetsDir } from '../../build.js';
5
5
 
6
6
  async function setupCssModules({
7
7
  rootDirectory,
8
8
  appDirectory
9
9
  }) {
10
10
  const workPromise = Promise.all([
11
- mergePackageJson(getAssetDir("css-modules"), rootDirectory),
11
+ mergePackageJson(await getAssetsDir("css-modules"), rootDirectory),
12
12
  getCodeFormatOptions(rootDirectory).then(
13
13
  (formatConfig) => injectCssBundlingLink(appDirectory, formatConfig)
14
14
  )
@@ -1,7 +1,7 @@
1
1
  import { outputInfo } from '@shopify/cli-kit/node/output';
2
2
  import { mergePackageJson } from '../../file.js';
3
3
  import { canWriteFiles, copyAssets } from './assets.js';
4
- import { getAssetDir } from '../../build.js';
4
+ import { getAssetsDir } from '../../build.js';
5
5
 
6
6
  async function setupPostCss({ rootDirectory, appDirectory, ...futureOptions }, force = false) {
7
7
  const assetMap = {
@@ -18,7 +18,7 @@ async function setupPostCss({ rootDirectory, appDirectory, ...futureOptions }, f
18
18
  return;
19
19
  }
20
20
  const workPromise = Promise.all([
21
- mergePackageJson(getAssetDir("postcss"), rootDirectory),
21
+ mergePackageJson(await getAssetsDir("postcss"), rootDirectory),
22
22
  copyAssets("postcss", assetMap, rootDirectory)
23
23
  ]);
24
24
  return {