@shopify/cli-hydrogen 5.2.2 → 5.3.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 +49 -25
- package/dist/commands/hydrogen/deploy.js +171 -0
- package/dist/commands/hydrogen/deploy.test.js +185 -0
- package/dist/commands/hydrogen/dev.js +27 -14
- package/dist/commands/hydrogen/init.js +10 -6
- package/dist/commands/hydrogen/init.test.js +16 -1
- package/dist/commands/hydrogen/preview.js +27 -11
- package/dist/generator-templates/starter/app/root.tsx +6 -4
- package/dist/generator-templates/starter/app/routes/account.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/cart.$lines.tsx +70 -0
- package/dist/generator-templates/starter/app/routes/cart.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/discount.$code.tsx +43 -0
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +3 -1
- package/dist/generator-templates/starter/package.json +4 -4
- package/dist/generator-templates/starter/remix.env.d.ts +12 -3
- package/dist/generator-templates/starter/server.ts +22 -19
- package/dist/generator-templates/starter/tsconfig.json +1 -1
- package/dist/lib/bundle/analyzer.js +56 -0
- package/dist/lib/bundle/bundle-analyzer.html +2045 -0
- package/dist/lib/flags.js +4 -0
- package/dist/lib/get-oxygen-token.js +47 -0
- package/dist/lib/get-oxygen-token.test.js +104 -0
- package/dist/lib/graphql/admin/oxygen-token.js +21 -0
- package/dist/lib/live-reload.js +2 -1
- package/dist/lib/log.js +56 -13
- package/dist/lib/mini-oxygen/common.js +58 -0
- package/dist/lib/mini-oxygen/index.js +12 -0
- package/dist/lib/mini-oxygen/node.js +110 -0
- package/dist/lib/mini-oxygen/types.js +1 -0
- package/dist/lib/mini-oxygen/workerd-inspector.js +392 -0
- package/dist/lib/mini-oxygen/workerd.js +182 -0
- package/dist/lib/onboarding/common.js +24 -13
- package/dist/lib/onboarding/local.js +1 -1
- package/dist/lib/remix-config.js +12 -2
- package/dist/lib/remix-version-check.js +7 -4
- package/dist/lib/remix-version-check.test.js +1 -1
- package/dist/lib/render-errors.js +1 -1
- package/dist/lib/request-events.js +84 -0
- package/dist/lib/setups/routes/generate.js +3 -3
- package/dist/lib/transpile-ts.js +21 -23
- package/dist/lib/virtual-routes.js +11 -9
- package/dist/virtual-routes/components/FlameChartWrapper.jsx +125 -0
- package/dist/virtual-routes/routes/debug-network.jsx +289 -0
- package/dist/virtual-routes/routes/index.jsx +4 -4
- package/dist/virtual-routes/virtual-root.jsx +7 -4
- package/oclif.manifest.json +81 -3
- package/package.json +35 -12
- package/dist/lib/mini-oxygen.js +0 -108
|
@@ -1,34 +1,50 @@
|
|
|
1
1
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
2
2
|
import { muteDevLogs } from '../../lib/log.js';
|
|
3
3
|
import { getProjectPaths } from '../../lib/remix-config.js';
|
|
4
|
-
import { commonFlags, DEFAULT_PORT } from '../../lib/flags.js';
|
|
5
|
-
import { startMiniOxygen } from '../../lib/mini-oxygen.js';
|
|
4
|
+
import { commonFlags, flagsToCamelObject, DEFAULT_PORT } from '../../lib/flags.js';
|
|
5
|
+
import { startMiniOxygen } from '../../lib/mini-oxygen/index.js';
|
|
6
|
+
import { getAllEnvironmentVariables } from '../../lib/environment-variables.js';
|
|
7
|
+
import { getConfig } from '../../lib/shopify-config.js';
|
|
6
8
|
|
|
7
9
|
class Preview extends Command {
|
|
8
10
|
static description = "Runs a Hydrogen storefront in an Oxygen worker for production.";
|
|
9
11
|
static flags = {
|
|
10
12
|
path: commonFlags.path,
|
|
11
|
-
port: commonFlags.port
|
|
13
|
+
port: commonFlags.port,
|
|
14
|
+
["worker-unstable"]: commonFlags.workerRuntime,
|
|
15
|
+
["env-branch"]: commonFlags.envBranch
|
|
12
16
|
};
|
|
13
17
|
async run() {
|
|
14
18
|
const { flags } = await this.parse(Preview);
|
|
15
|
-
await runPreview({
|
|
19
|
+
await runPreview({
|
|
20
|
+
...flagsToCamelObject(flags),
|
|
21
|
+
workerRuntime: flags["worker-unstable"]
|
|
22
|
+
});
|
|
16
23
|
}
|
|
17
24
|
}
|
|
18
25
|
async function runPreview({
|
|
19
26
|
port = DEFAULT_PORT,
|
|
20
|
-
path: appPath
|
|
27
|
+
path: appPath,
|
|
28
|
+
workerRuntime = false,
|
|
29
|
+
envBranch
|
|
21
30
|
}) {
|
|
22
31
|
if (!process.env.NODE_ENV)
|
|
23
32
|
process.env.NODE_ENV = "production";
|
|
24
33
|
muteDevLogs({ workerReload: false });
|
|
25
34
|
const { root, buildPathWorkerFile, buildPathClient } = getProjectPaths(appPath);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const { shop, storefront } = await getConfig(root);
|
|
36
|
+
const fetchRemote = !!shop && !!storefront?.id;
|
|
37
|
+
const env = await getAllEnvironmentVariables({ root, fetchRemote, envBranch });
|
|
38
|
+
const miniOxygen = await startMiniOxygen(
|
|
39
|
+
{
|
|
40
|
+
root,
|
|
41
|
+
port,
|
|
42
|
+
buildPathClient,
|
|
43
|
+
buildPathWorkerFile,
|
|
44
|
+
env
|
|
45
|
+
},
|
|
46
|
+
workerRuntime
|
|
47
|
+
);
|
|
32
48
|
miniOxygen.showBanner({ mode: "preview" });
|
|
33
49
|
}
|
|
34
50
|
|
|
@@ -63,8 +63,8 @@ export async function loader({context}: LoaderArgs) {
|
|
|
63
63
|
|
|
64
64
|
// validate the customer access token is valid
|
|
65
65
|
const {isLoggedIn, headers} = await validateCustomerAccessToken(
|
|
66
|
-
customerAccessToken,
|
|
67
66
|
session,
|
|
67
|
+
customerAccessToken,
|
|
68
68
|
);
|
|
69
69
|
|
|
70
70
|
// defer the cart query by not awaiting it
|
|
@@ -198,17 +198,19 @@ export function CatchBoundary() {
|
|
|
198
198
|
* ```
|
|
199
199
|
* */
|
|
200
200
|
async function validateCustomerAccessToken(
|
|
201
|
-
customerAccessToken: CustomerAccessToken,
|
|
202
201
|
session: HydrogenSession,
|
|
202
|
+
customerAccessToken?: CustomerAccessToken,
|
|
203
203
|
) {
|
|
204
204
|
let isLoggedIn = false;
|
|
205
205
|
const headers = new Headers();
|
|
206
206
|
if (!customerAccessToken?.accessToken || !customerAccessToken?.expiresAt) {
|
|
207
207
|
return {isLoggedIn, headers};
|
|
208
208
|
}
|
|
209
|
-
|
|
210
|
-
const
|
|
209
|
+
|
|
210
|
+
const expiresAt = new Date(customerAccessToken.expiresAt).getTime();
|
|
211
|
+
const dateNow = Date.now();
|
|
211
212
|
const customerAccessTokenExpired = expiresAt < dateNow;
|
|
213
|
+
|
|
212
214
|
if (customerAccessTokenExpired) {
|
|
213
215
|
session.unset('customerAccessToken');
|
|
214
216
|
headers.append('Set-Cookie', await session.commit());
|
|
@@ -10,7 +10,7 @@ export async function loader({request, context}: LoaderArgs) {
|
|
|
10
10
|
const {session, storefront} = context;
|
|
11
11
|
const {pathname} = new URL(request.url);
|
|
12
12
|
const customerAccessToken = await session.get('customerAccessToken');
|
|
13
|
-
const isLoggedIn =
|
|
13
|
+
const isLoggedIn = !!customerAccessToken?.accessToken;
|
|
14
14
|
const isAccountHome = pathname === '/account' || pathname === '/account/';
|
|
15
15
|
const isPrivateRoute =
|
|
16
16
|
/^\/account\/(orders|orders\/.*|profile|addresses|addresses\/.*)$/.test(
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {redirect, type LoaderArgs} from '@shopify/remix-oxygen';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Automatically creates a new cart based on the URL and redirects straight to checkout.
|
|
5
|
+
* Expected URL structure:
|
|
6
|
+
* ```ts
|
|
7
|
+
* /cart/<variant_id>:<quantity>
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* More than one `<variant_id>:<quantity>` separated by a comma, can be supplied in the URL, for
|
|
11
|
+
* carts with more than one product variant.
|
|
12
|
+
*
|
|
13
|
+
* @param `?discount` an optional discount code to apply to the cart
|
|
14
|
+
* @example
|
|
15
|
+
* Example path creating a cart with two product variants, different quantities, and a discount code:
|
|
16
|
+
* ```ts
|
|
17
|
+
* /cart/41007289663544:1,41007289696312:2?discount=HYDROBOARD
|
|
18
|
+
*
|
|
19
|
+
* ```
|
|
20
|
+
* @preserve
|
|
21
|
+
*/
|
|
22
|
+
export async function loader({request, context, params}: LoaderArgs) {
|
|
23
|
+
const {cart} = context;
|
|
24
|
+
const {lines} = params;
|
|
25
|
+
if (!lines) return redirect('/cart');
|
|
26
|
+
const linesMap = lines.split(',').map((line) => {
|
|
27
|
+
const lineDetails = line.split(':');
|
|
28
|
+
const variantId = lineDetails[0];
|
|
29
|
+
const quantity = parseInt(lineDetails[1], 10);
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
merchandiseId: `gid://shopify/ProductVariant/${variantId}`,
|
|
33
|
+
quantity,
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const url = new URL(request.url);
|
|
38
|
+
const searchParams = new URLSearchParams(url.search);
|
|
39
|
+
|
|
40
|
+
const discount = searchParams.get('discount');
|
|
41
|
+
const discountArray = discount ? [discount] : [];
|
|
42
|
+
|
|
43
|
+
// create a cart
|
|
44
|
+
const result = await cart.create({
|
|
45
|
+
lines: linesMap,
|
|
46
|
+
discountCodes: discountArray,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const cartResult = result.cart;
|
|
50
|
+
|
|
51
|
+
if (result.errors?.length || !cartResult) {
|
|
52
|
+
throw new Response('Link may be expired. Try checking the URL.', {
|
|
53
|
+
status: 410,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Update cart id in cookie
|
|
58
|
+
const headers = cart.setCartId(cartResult.id);
|
|
59
|
+
|
|
60
|
+
// redirect to checkout
|
|
61
|
+
if (cartResult.checkoutUrl) {
|
|
62
|
+
return redirect(cartResult.checkoutUrl, {headers});
|
|
63
|
+
} else {
|
|
64
|
+
throw new Error('No checkout URL found');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default function Component() {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
@@ -54,7 +54,7 @@ export async function action({request, context}: ActionArgs) {
|
|
|
54
54
|
case CartForm.ACTIONS.BuyerIdentityUpdate: {
|
|
55
55
|
result = await cart.updateBuyerIdentity({
|
|
56
56
|
...inputs.buyerIdentity,
|
|
57
|
-
customerAccessToken,
|
|
57
|
+
customerAccessToken: customerAccessToken?.accessToken,
|
|
58
58
|
});
|
|
59
59
|
break;
|
|
60
60
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {redirect, type LoaderArgs} from '@shopify/remix-oxygen';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Automatically applies a discount found on the url
|
|
5
|
+
* If a cart exists it's updated with the discount, otherwise a cart is created with the discount already applied
|
|
6
|
+
* @param ?redirect an optional path to return to otherwise return to the home page
|
|
7
|
+
* @example
|
|
8
|
+
* Example path applying a discount and redirecting
|
|
9
|
+
* ```ts
|
|
10
|
+
* /discount/FREESHIPPING?redirect=/products
|
|
11
|
+
*
|
|
12
|
+
* ```
|
|
13
|
+
* @preserve
|
|
14
|
+
*/
|
|
15
|
+
export async function loader({request, context, params}: LoaderArgs) {
|
|
16
|
+
const {cart} = context;
|
|
17
|
+
const {code} = params;
|
|
18
|
+
|
|
19
|
+
const url = new URL(request.url);
|
|
20
|
+
const searchParams = new URLSearchParams(url.search);
|
|
21
|
+
const redirectParam =
|
|
22
|
+
searchParams.get('redirect') || searchParams.get('return_to') || '/';
|
|
23
|
+
|
|
24
|
+
searchParams.delete('redirect');
|
|
25
|
+
searchParams.delete('return_to');
|
|
26
|
+
|
|
27
|
+
const redirectUrl = `${redirectParam}?${searchParams}`;
|
|
28
|
+
|
|
29
|
+
if (!code) {
|
|
30
|
+
return redirect(redirectUrl);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const result = await cart.updateDiscountCodes([code]);
|
|
34
|
+
const headers = cart.setCartId(result.cart.id);
|
|
35
|
+
|
|
36
|
+
// Using set-cookie on a 303 redirect will not work if the domain origin have port number (:3000)
|
|
37
|
+
// If there is no cart id and a new cart id is created in the progress, it will not be set in the cookie
|
|
38
|
+
// on localhost:3000
|
|
39
|
+
return redirect(redirectUrl, {
|
|
40
|
+
status: 303,
|
|
41
|
+
headers,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -42,7 +42,9 @@ export async function loader({params, request, context}: LoaderArgs) {
|
|
|
42
42
|
!option.name.startsWith('_pos') &&
|
|
43
43
|
!option.name.startsWith('_psq') &&
|
|
44
44
|
!option.name.startsWith('_ss') &&
|
|
45
|
-
!option.name.startsWith('_v')
|
|
45
|
+
!option.name.startsWith('_v') &&
|
|
46
|
+
// Filter out third party tracking params
|
|
47
|
+
!option.name.startsWith('fbclid'),
|
|
46
48
|
);
|
|
47
49
|
|
|
48
50
|
if (!handle) {
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"prettier": "@shopify/prettier-config",
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@remix-run/react": "1.19.1",
|
|
17
|
-
"@shopify/cli": "3.
|
|
18
|
-
"@shopify/cli-hydrogen": "^5.
|
|
19
|
-
"@shopify/hydrogen": "^2023.7.
|
|
20
|
-
"@shopify/remix-oxygen": "^1.1.
|
|
17
|
+
"@shopify/cli": "3.49.2",
|
|
18
|
+
"@shopify/cli-hydrogen": "^5.3.0",
|
|
19
|
+
"@shopify/hydrogen": "^2023.7.8",
|
|
20
|
+
"@shopify/remix-oxygen": "^1.1.4",
|
|
21
21
|
"graphql": "^16.6.0",
|
|
22
22
|
"graphql-tag": "^2.12.6",
|
|
23
23
|
"isbot": "^3.6.6",
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import '@total-typescript/ts-reset';
|
|
7
7
|
|
|
8
8
|
import type {Storefront, HydrogenCart} from '@shopify/hydrogen';
|
|
9
|
+
import type {CustomerAccessToken} from '@shopify/hydrogen/storefront-api-types';
|
|
9
10
|
import type {HydrogenSession} from './server';
|
|
10
11
|
|
|
11
12
|
declare global {
|
|
@@ -26,14 +27,22 @@ declare global {
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
/**
|
|
30
|
-
* Declare local additions to `AppLoadContext` to include the session utilities we injected in `server.ts`.
|
|
31
|
-
*/
|
|
32
30
|
declare module '@shopify/remix-oxygen' {
|
|
31
|
+
/**
|
|
32
|
+
* Declare local additions to the Remix loader context.
|
|
33
|
+
*/
|
|
33
34
|
export interface AppLoadContext {
|
|
34
35
|
env: Env;
|
|
35
36
|
cart: HydrogenCart;
|
|
36
37
|
storefront: Storefront;
|
|
37
38
|
session: HydrogenSession;
|
|
39
|
+
waitUntil: ExecutionContext['waitUntil'];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Declare the data we expect to access via `context.session`.
|
|
44
|
+
*/
|
|
45
|
+
export interface SessionData {
|
|
46
|
+
customerAccessToken: CustomerAccessToken;
|
|
38
47
|
}
|
|
39
48
|
}
|
|
@@ -32,7 +32,7 @@ export default {
|
|
|
32
32
|
throw new Error('SESSION_SECRET environment variable is not set');
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
const waitUntil =
|
|
35
|
+
const waitUntil = executionContext.waitUntil.bind(executionContext);
|
|
36
36
|
const [cache, session] = await Promise.all([
|
|
37
37
|
caches.open('hydrogen'),
|
|
38
38
|
HydrogenSession.init(request, [env.SESSION_SECRET]),
|
|
@@ -70,7 +70,7 @@ export default {
|
|
|
70
70
|
const handleRequest = createRequestHandler({
|
|
71
71
|
build: remixBuild,
|
|
72
72
|
mode: process.env.NODE_ENV,
|
|
73
|
-
getLoadContext: () => ({session, storefront, env,
|
|
73
|
+
getLoadContext: () => ({session, storefront, cart, env, waitUntil}),
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
const response = await handleRequest(request);
|
|
@@ -99,10 +99,13 @@ export default {
|
|
|
99
99
|
* swap out the cookie-based implementation with something else!
|
|
100
100
|
*/
|
|
101
101
|
export class HydrogenSession {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
) {
|
|
102
|
+
#sessionStorage;
|
|
103
|
+
#session;
|
|
104
|
+
|
|
105
|
+
constructor(sessionStorage: SessionStorage, session: Session) {
|
|
106
|
+
this.#sessionStorage = sessionStorage;
|
|
107
|
+
this.#session = session;
|
|
108
|
+
}
|
|
106
109
|
|
|
107
110
|
static async init(request: Request, secrets: string[]) {
|
|
108
111
|
const storage = createCookieSessionStorage({
|
|
@@ -120,32 +123,32 @@ export class HydrogenSession {
|
|
|
120
123
|
return new this(storage, session);
|
|
121
124
|
}
|
|
122
125
|
|
|
123
|
-
has(
|
|
124
|
-
return this
|
|
126
|
+
get has() {
|
|
127
|
+
return this.#session.has;
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
get(
|
|
128
|
-
return this
|
|
130
|
+
get get() {
|
|
131
|
+
return this.#session.get;
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
|
|
132
|
-
return this.
|
|
134
|
+
get flash() {
|
|
135
|
+
return this.#session.flash;
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
|
|
136
|
-
this
|
|
138
|
+
get unset() {
|
|
139
|
+
return this.#session.unset;
|
|
137
140
|
}
|
|
138
141
|
|
|
139
|
-
|
|
140
|
-
this
|
|
142
|
+
get set() {
|
|
143
|
+
return this.#session.set;
|
|
141
144
|
}
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
this.session
|
|
146
|
+
destroy() {
|
|
147
|
+
return this.#sessionStorage.destroySession(this.#session);
|
|
145
148
|
}
|
|
146
149
|
|
|
147
150
|
commit() {
|
|
148
|
-
return this
|
|
151
|
+
return this.#sessionStorage.commitSession(this.#session);
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
154
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { joinPath, dirname } from '@shopify/cli-kit/node/path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { readFile, writeFile } from '@shopify/cli-kit/node/fs';
|
|
4
|
+
import colors from '@shopify/cli-kit/node/colors';
|
|
5
|
+
|
|
6
|
+
async function buildBundleAnalysis(buildPath) {
|
|
7
|
+
await Promise.all([
|
|
8
|
+
writeBundleAnalyzerFile(
|
|
9
|
+
buildPath,
|
|
10
|
+
"metafile.server.json",
|
|
11
|
+
"worker-bundle-analyzer.html"
|
|
12
|
+
),
|
|
13
|
+
writeBundleAnalyzerFile(
|
|
14
|
+
buildPath,
|
|
15
|
+
"metafile.js.json",
|
|
16
|
+
"client-bundle-analyzer.html"
|
|
17
|
+
)
|
|
18
|
+
]);
|
|
19
|
+
return "file://" + joinPath(buildPath, "worker", "worker-bundle-analyzer.html");
|
|
20
|
+
}
|
|
21
|
+
async function writeBundleAnalyzerFile(buildPath, metafileName, outputFile) {
|
|
22
|
+
const metafile = await readFile(joinPath(buildPath, "worker", metafileName), {
|
|
23
|
+
encoding: "utf8"
|
|
24
|
+
});
|
|
25
|
+
const metafile64 = Buffer.from(metafile, "utf-8").toString("base64");
|
|
26
|
+
const analysisTemplate = await readFile(
|
|
27
|
+
fileURLToPath(
|
|
28
|
+
new URL(`../../lib/bundle/bundle-analyzer.html`, import.meta.url)
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
const templateWithMetafile = analysisTemplate.replace(
|
|
32
|
+
`globalThis.METAFILE = '';`,
|
|
33
|
+
`globalThis.METAFILE = '${metafile64}';`
|
|
34
|
+
);
|
|
35
|
+
await writeFile(
|
|
36
|
+
joinPath(buildPath, "worker", outputFile),
|
|
37
|
+
templateWithMetafile
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
async function getBundleAnalysisSummary(bundlePath) {
|
|
41
|
+
const esbuild = await import('esbuild').catch(() => {
|
|
42
|
+
});
|
|
43
|
+
if (esbuild) {
|
|
44
|
+
const metafilePath = joinPath(dirname(bundlePath), "metafile.server.json");
|
|
45
|
+
return " \u2502\n " + (await esbuild.analyzeMetafile(await readFile(metafilePath), {
|
|
46
|
+
color: true
|
|
47
|
+
})).split("\n").filter((line) => {
|
|
48
|
+
const match = line.match(
|
|
49
|
+
/(.*)\/node_modules\/(react-dom|@remix-run|@shopify\/hydrogen|react-router|react-router-dom)\/(.*)/g
|
|
50
|
+
);
|
|
51
|
+
return !match;
|
|
52
|
+
}).slice(2, 12).join("\n").replace(/dist\/worker\/_assets\/.*$/ms, "\n").replace(/\n/g, "\n ").replace(/(\.\.\/)+node_modules\//g, (match) => colors.dim(match));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { buildBundleAnalysis, getBundleAnalysisSummary };
|