Skip to content

Commit

Permalink
Open theme profile in Speedscope by default
Browse files Browse the repository at this point in the history
  • Loading branch information
macournoyer committed Dec 16, 2024
1 parent c8e0104 commit f32eda5
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 6 deletions.
3 changes: 2 additions & 1 deletion packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2065,9 +2065,10 @@ Profile the Liquid rendering of a theme page.

```
USAGE
$ shopify theme profile -u <value> [--no-color] [--verbose]
$ shopify theme profile -u <value> [-j] [--no-color] [--verbose]
FLAGS
-j, --json Return profiling data as JSON.
-u, --url=<value> (required) URL to the theme page to profile.
--no-color Disable color output.
--verbose Increase the verbosity of the output.
Expand Down
8 changes: 8 additions & 0 deletions packages/cli/oclif.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5755,6 +5755,14 @@
"description": "TODO",
"descriptionWithMarkdown": "TODO",
"flags": {
"json": {
"allowNo": false,
"char": "j",
"description": "Return profiling data as JSON.",
"env": "SHOPIFY_FLAG_JSON",
"name": "json",
"type": "boolean"
},
"no-color": {
"allowNo": false,
"description": "Disable color output.",
Expand Down
1 change: 1 addition & 0 deletions packages/theme/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@shopify/theme-language-server-node": "2.3.2",
"chokidar": "3.5.3",
"h3": "1.12.0",
"speedscope": "^1.21.0",
"yaml": "2.3.2"
},
"devDependencies": {
Expand Down
9 changes: 7 additions & 2 deletions packages/theme/src/cli/commands/theme/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Flags} from '@oclif/core'
import {globalFlags} from '@shopify/cli-kit/node/cli'

export default class Profile extends ThemeCommand {
static summary = 'Profile the Liquid rendering of a theme page, and return JSON profiling data.'
static summary = 'Profile the Liquid rendering of a theme page.'

static descriptionWithMarkdown = `TODO`

Expand All @@ -18,11 +18,16 @@ export default class Profile extends ThemeCommand {
env: 'SHOPIFY_FLAG_URL',
required: true,
}),
json: Flags.boolean({
char: 'j',
description: 'Return profiling data as JSON.',
env: 'SHOPIFY_FLAG_JSON',
}),
}

async run(): Promise<void> {
const {flags} = await this.parse(Profile)

await profile(flags.url)
await profile(flags.url, flags.json)
}
}
42 changes: 39 additions & 3 deletions packages/theme/src/cli/services/profile.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,45 @@
export async function profile(storeUrl: string) {
import * as fs from 'fs/promises'
import * as path from 'path'

Check failure on line 2 in packages/theme/src/cli/services/profile.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/theme/src/cli/services/profile.ts#L2

[no-restricted-imports] 'path' import is restricted from being used. Please use: import { joinPath } from '@shopify/cli-kit/node/path'
import * as os from 'os'
import {fileURLToPath} from 'url'
import {openURL} from '@shopify/cli-kit/node/system'

Check failure on line 5 in packages/theme/src/cli/services/profile.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/theme/src/cli/services/profile.ts#L5

[import/order] `@shopify/cli-kit/node/system` import should occur before import of `fs/promises`

export async function profile(storeUrl: string, asJson: boolean) {
// Fetch the profiling from the Store
const url = new URL(storeUrl)
url.searchParams.append('profile_liquid', '1')
const response = await fetch(url)
const profileJson = await response.text()
// use process.stdout.write to print the JSON
process.stdout.write(profileJson)

if (asJson) {
// Print the JSON
process.stdout.write(profileJson)
} else {
await openProfile(profileJson)
}
}

async function openProfile(profileJson: string) {
// Adapted from https://github.com/jlfwong/speedscope/blob/146477a8508a6d2da697cb0ea0a426ba81b3e8dc/bin/cli.js#L63
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
let urlToOpen = 'file://' + path.resolve(__dirname, '../../../node_modules/speedscope/dist/release/index.html')

Check failure on line 26 in packages/theme/src/cli/services/profile.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/theme/src/cli/services/profile.ts#L26

[prefer-template] Unexpected string concatenation.
const filename = 'liquid-profile'

const sourceBase64 = Buffer.from(profileJson).toString('base64')
const jsSource = `speedscope.loadFileFromBase64(${JSON.stringify(filename)}, ${JSON.stringify(sourceBase64)})`

const filePrefix = `speedscope-${+new Date()}-${process.pid}`

Check failure on line 32 in packages/theme/src/cli/services/profile.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/theme/src/cli/services/profile.ts#L32

[no-implicit-coercion] use `Number(new Date())` instead.
const jsPath = path.join(os.tmpdir(), `${filePrefix}.js`)
await fs.writeFile(jsPath, jsSource)
urlToOpen += `#localProfilePath=${jsPath}`

// For some silly reason, the OS X open command ignores any query parameters or hash parameters
// passed as part of the URL. To get around this weird issue, we'll create a local HTML file
// that just redirects.
const htmlPath = path.join(os.tmpdir(), `${filePrefix}.html`)
await fs.writeFile(htmlPath, `<script>window.location=${JSON.stringify(urlToOpen)}</script>`)

urlToOpen = `file://${htmlPath}`
await openURL(urlToOpen)
}
18 changes: 18 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f32eda5

Please sign in to comment.