windmill-cli 1.760.1 → 1.761.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/esm/main.js +49 -36
- package/package.json +1 -1
package/esm/main.js
CHANGED
|
@@ -16784,7 +16784,7 @@ var init_OpenAPI = __esm(() => {
|
|
|
16784
16784
|
PASSWORD: undefined,
|
|
16785
16785
|
TOKEN: getEnv3("WM_TOKEN"),
|
|
16786
16786
|
USERNAME: undefined,
|
|
16787
|
-
VERSION: "1.
|
|
16787
|
+
VERSION: "1.761.0",
|
|
16788
16788
|
WITH_CREDENTIALS: true,
|
|
16789
16789
|
interceptors: {
|
|
16790
16790
|
request: new Interceptors,
|
|
@@ -17152,7 +17152,6 @@ __export(exports_services_gen, {
|
|
|
17152
17152
|
setFlowUserState: () => setFlowUserState,
|
|
17153
17153
|
setEnvironmentVariable: () => setEnvironmentVariable,
|
|
17154
17154
|
setEmailTriggerMode: () => setEmailTriggerMode,
|
|
17155
|
-
setDevWorkspaceLabel: () => setDevWorkspaceLabel,
|
|
17156
17155
|
setDefaultErrorOrRecoveryHandler: () => setDefaultErrorOrRecoveryHandler,
|
|
17157
17156
|
setCaptureConfig: () => setCaptureConfig,
|
|
17158
17157
|
setAzureTriggerMode: () => setAzureTriggerMode,
|
|
@@ -18239,16 +18238,6 @@ var backendVersion = () => {
|
|
|
18239
18238
|
workspace: data3.workspace
|
|
18240
18239
|
}
|
|
18241
18240
|
});
|
|
18242
|
-
}, setDevWorkspaceLabel = (data3) => {
|
|
18243
|
-
return request(OpenAPI, {
|
|
18244
|
-
method: "POST",
|
|
18245
|
-
url: "/w/{workspace}/workspaces/set_dev_workspace_label",
|
|
18246
|
-
path: {
|
|
18247
|
-
workspace: data3.workspace
|
|
18248
|
-
},
|
|
18249
|
-
body: data3.requestBody,
|
|
18250
|
-
mediaType: "application/json"
|
|
18251
|
-
});
|
|
18252
18241
|
}, existsWorkspace = (data3) => {
|
|
18253
18242
|
return request(OpenAPI, {
|
|
18254
18243
|
method: "POST",
|
|
@@ -20580,7 +20569,8 @@ var backendVersion = () => {
|
|
|
20580
20569
|
workspace: data3.workspace
|
|
20581
20570
|
},
|
|
20582
20571
|
query: {
|
|
20583
|
-
all_users: data3.allUsers
|
|
20572
|
+
all_users: data3.allUsers,
|
|
20573
|
+
compare_to_workspace: data3.compareToWorkspace
|
|
20584
20574
|
}
|
|
20585
20575
|
});
|
|
20586
20576
|
}, getDraftForUser = (data3) => {
|
|
@@ -25889,7 +25879,6 @@ __export(exports_gen, {
|
|
|
25889
25879
|
setFlowUserState: () => setFlowUserState,
|
|
25890
25880
|
setEnvironmentVariable: () => setEnvironmentVariable,
|
|
25891
25881
|
setEmailTriggerMode: () => setEmailTriggerMode,
|
|
25892
|
-
setDevWorkspaceLabel: () => setDevWorkspaceLabel,
|
|
25893
25882
|
setDefaultErrorOrRecoveryHandler: () => setDefaultErrorOrRecoveryHandler,
|
|
25894
25883
|
setCaptureConfig: () => setCaptureConfig,
|
|
25895
25884
|
setAzureTriggerMode: () => setAzureTriggerMode,
|
|
@@ -26678,7 +26667,7 @@ var init_auth = __esm(async () => {
|
|
|
26678
26667
|
});
|
|
26679
26668
|
|
|
26680
26669
|
// src/core/constants.ts
|
|
26681
|
-
var WM_FORK_PREFIX = "wm-fork", VERSION = "1.
|
|
26670
|
+
var WM_FORK_PREFIX = "wm-fork", VERSION = "1.761.0";
|
|
26682
26671
|
|
|
26683
26672
|
// src/utils/git.ts
|
|
26684
26673
|
var exports_git = {};
|
|
@@ -26759,22 +26748,28 @@ function isGitRepository() {
|
|
|
26759
26748
|
return false;
|
|
26760
26749
|
}
|
|
26761
26750
|
}
|
|
26762
|
-
function isForkWorkspace(workspaceId) {
|
|
26763
|
-
return workspaceId.startsWith(FORK_WORKSPACE_PREFIX);
|
|
26751
|
+
function isForkWorkspace(workspaceId, parentWorkspaceId) {
|
|
26752
|
+
return !!parentWorkspaceId || workspaceId.startsWith(FORK_WORKSPACE_PREFIX);
|
|
26764
26753
|
}
|
|
26765
|
-
function forkBranchName(workspaceId, originalBranch) {
|
|
26766
|
-
|
|
26754
|
+
function forkBranchName(workspaceId, originalBranch, devWorkspaceLabel) {
|
|
26755
|
+
if (devWorkspaceLabel) {
|
|
26756
|
+
return devWorkspaceLabel;
|
|
26757
|
+
}
|
|
26758
|
+
const branchPrefix = `${WM_FORK_PREFIX}/${originalBranch}/`;
|
|
26759
|
+
return workspaceId.startsWith(FORK_WORKSPACE_PREFIX) ? workspaceId.replace(FORK_WORKSPACE_PREFIX, branchPrefix) : `${branchPrefix}${workspaceId}`;
|
|
26767
26760
|
}
|
|
26768
26761
|
function computeGitSyncDeployBranch(params) {
|
|
26769
26762
|
const {
|
|
26770
26763
|
workspaceId,
|
|
26764
|
+
parentWorkspaceId,
|
|
26765
|
+
devWorkspaceLabel,
|
|
26771
26766
|
items,
|
|
26772
26767
|
useIndividualBranch,
|
|
26773
26768
|
groupByFolder,
|
|
26774
26769
|
clonedBranchName
|
|
26775
26770
|
} = params;
|
|
26776
|
-
if (workspaceId
|
|
26777
|
-
return forkBranchName(workspaceId, clonedBranchName);
|
|
26771
|
+
if (isForkWorkspace(workspaceId, parentWorkspaceId)) {
|
|
26772
|
+
return forkBranchName(workspaceId, clonedBranchName, devWorkspaceLabel);
|
|
26778
26773
|
}
|
|
26779
26774
|
if (items.length === 0)
|
|
26780
26775
|
return null;
|
|
@@ -69593,28 +69588,32 @@ async function pull(opts) {
|
|
|
69593
69588
|
process.exit(1);
|
|
69594
69589
|
}
|
|
69595
69590
|
const clonedBranchName = getCurrentGitBranch() ?? "main";
|
|
69596
|
-
const targetIsFork = isForkWorkspace(workspace.workspaceId);
|
|
69591
|
+
const targetIsFork = isForkWorkspace(workspace.workspaceId, opts.parentWorkspaceId);
|
|
69597
69592
|
const useIndividualBranch = targetIsFork ? false : !!opts.useIndividualBranch;
|
|
69598
69593
|
const groupByFolder = targetIsFork ? false : !!opts.groupByFolder;
|
|
69599
|
-
|
|
69600
|
-
|
|
69601
|
-
|
|
69602
|
-
|
|
69603
|
-
|
|
69604
|
-
|
|
69605
|
-
|
|
69606
|
-
|
|
69607
|
-
|
|
69608
|
-
checkoutGitSyncDeployBranch(parentBranch);
|
|
69609
|
-
}
|
|
69594
|
+
const parentBranch = opts.parentDevWorkspaceLabel ? opts.parentDevWorkspaceLabel : opts.parentWorkspaceId && isForkWorkspace(opts.parentWorkspaceId) ? computeGitSyncDeployBranch({
|
|
69595
|
+
workspaceId: opts.parentWorkspaceId,
|
|
69596
|
+
items: deployItems,
|
|
69597
|
+
useIndividualBranch,
|
|
69598
|
+
groupByFolder,
|
|
69599
|
+
clonedBranchName
|
|
69600
|
+
}) : null;
|
|
69601
|
+
if (parentBranch && parentBranch !== clonedBranchName) {
|
|
69602
|
+
checkoutGitSyncDeployBranch(parentBranch);
|
|
69610
69603
|
}
|
|
69611
69604
|
const deployBranch = computeGitSyncDeployBranch({
|
|
69612
69605
|
workspaceId: workspace.workspaceId,
|
|
69606
|
+
parentWorkspaceId: opts.parentWorkspaceId,
|
|
69607
|
+
devWorkspaceLabel: opts.devWorkspaceLabel,
|
|
69613
69608
|
items: deployItems,
|
|
69614
69609
|
useIndividualBranch,
|
|
69615
69610
|
groupByFolder,
|
|
69616
69611
|
clonedBranchName
|
|
69617
69612
|
});
|
|
69613
|
+
if (targetIsFork && deployBranch && deployBranch === clonedBranchName) {
|
|
69614
|
+
error(`Fork branch '${deployBranch}' equals the checked-out branch '${clonedBranchName}'; refusing to deploy a fork directly to the tracked branch. Use a different dev workspace label or tracked branch.`);
|
|
69615
|
+
process.exit(1);
|
|
69616
|
+
}
|
|
69618
69617
|
if (deployBranch && deployBranch !== clonedBranchName) {
|
|
69619
69618
|
checkoutGitSyncDeployBranch(deployBranch);
|
|
69620
69619
|
}
|
|
@@ -69871,7 +69870,7 @@ async function gitDeploy(opts) {
|
|
|
69871
69870
|
process.exit(1);
|
|
69872
69871
|
}
|
|
69873
69872
|
}
|
|
69874
|
-
const isFork = isForkWorkspace(opts.workspace ?? "");
|
|
69873
|
+
const isFork = isForkWorkspace(opts.workspace ?? "", opts.parentWorkspaceId);
|
|
69875
69874
|
const useIndividualBranch = isFork ? false : !!opts.useIndividualBranch;
|
|
69876
69875
|
const includes = deriveGitSyncDeployIncludes(items, useIndividualBranch);
|
|
69877
69876
|
const promotion = useIndividualBranch && !opts.promotion ? getCurrentGitBranch() ?? undefined : opts.promotion;
|
|
@@ -70958,7 +70957,7 @@ var init_sync = __esm(async () => {
|
|
|
70958
70957
|
aliasDuplicateObjects: false,
|
|
70959
70958
|
singleQuote: true
|
|
70960
70959
|
};
|
|
70961
|
-
command8 = new Command().description("sync local with a remote workspaces or the opposite (push or pull)").action(() => info("2 actions available, pull and push. Use -h to display help.")).command("pull").description("Pull any remote changes and apply them locally.").option("--yes", "Pull without needing confirmation").option("--dry-run", "Show changes that would be pulled without actually pushing").option("--plain-secrets", "Pull secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--include-secrets", "Include secrets in sync (overrides skipSecrets in wmill.yaml)").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Overrides wmill.yaml includes").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which file to NOT take into account. Overrides wmill.yaml excludes").option("--extra-includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--promotion <branch:string>", "Use promotionOverrides from the specified branch instead of regular overrides").option("--branch, --env <branch:string>", "[Deprecated: use --workspace] Override the current git branch/environment").action(pull).command("push").description("Push any local changes and apply them remotely.").option("--yes", "Push without needing confirmation").option("--dry-run", "Show changes that would be pushed without actually pushing").option("--plain-secrets", "Push secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--include-secrets", "Include secrets in sync (overrides skipSecrets in wmill.yaml)").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-reencrypt-on-key-change", "When the pushed encryption key differs from the remote, do NOT re-encrypt existing remote secrets. Only safe if they are already encrypted with the new key (e.g. workspace/instance migration). Default is to re-encrypt.").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string)").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which file to NOT take into account.").option("--extra-includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--message <message:string>", "Include a message that will be added to all scripts/flows/apps updated during this push").option("--parallel <number>", "Number of changes to process in parallel").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--branch, --env <branch:string>", "[Deprecated: use --workspace] Override the current git branch/environment").option("--lint", "Run lint validation before pushing").option("--locks-required", "Fail if scripts or flow inline scripts that need locks have no locks").option("--auto-metadata", "Automatically regenerate stale metadata (locks and schemas) before pushing").option("--accept-overriding-permissioned-as-with-self", "Accept that items with a different permissioned_as will be updated with your own user").action(push4).command("git-deploy").hidden().description("Internal git-sync deployment-callback step (used by the git-sync hub script). Runs inside an existing clone: switches to the wm_deploy/fork branch when applicable, pulls workspace content, then commits and pushes.").option("--repository <repo:string>", "Repository resource path (e.g. u/user/repo)").option("--git-deploy-items <json:string>", "JSON array of {path_type,path,parent_path,commit_msg} being deployed").option("--use-individual-branch", "Push each deployed object to its own wm_deploy/<workspace>/<...> branch").option("--group-by-folder", "With --use-individual-branch, group deployed objects per folder branch").option("--only-create-branch", "Only create/push the deploy branch, skip pulling and committing files").option("--parent-workspace-id <id:string>", "Parent workspace id, used to root a fork-of-a-fork branch").option("--skip-secrets", "Skip syncing only secrets variables").option("--git-committer-email <email:string>", "Committer email for the deploy commit (GPG-signed repos pass the GPG key email; defaults to WM_EMAIL)").option("--git-committer-name <name:string>", "Committer name for the deploy commit (defaults to WM_USERNAME)").action(gitDeploy);
|
|
70960
|
+
command8 = new Command().description("sync local with a remote workspaces or the opposite (push or pull)").action(() => info("2 actions available, pull and push. Use -h to display help.")).command("pull").description("Pull any remote changes and apply them locally.").option("--yes", "Pull without needing confirmation").option("--dry-run", "Show changes that would be pulled without actually pushing").option("--plain-secrets", "Pull secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--include-secrets", "Include secrets in sync (overrides skipSecrets in wmill.yaml)").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Overrides wmill.yaml includes").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which file to NOT take into account. Overrides wmill.yaml excludes").option("--extra-includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--promotion <branch:string>", "Use promotionOverrides from the specified branch instead of regular overrides").option("--branch, --env <branch:string>", "[Deprecated: use --workspace] Override the current git branch/environment").action(pull).command("push").description("Push any local changes and apply them remotely.").option("--yes", "Push without needing confirmation").option("--dry-run", "Show changes that would be pushed without actually pushing").option("--plain-secrets", "Push secrets as plain text").option("--json", "Use JSON instead of YAML").option("--skip-variables", "Skip syncing variables (including secrets)").option("--skip-secrets", "Skip syncing only secrets variables").option("--include-secrets", "Include secrets in sync (overrides skipSecrets in wmill.yaml)").option("--skip-resources", "Skip syncing resources").option("--skip-resource-types", "Skip syncing resource types").option("--skip-scripts", "Skip syncing scripts").option("--skip-flows", "Skip syncing flows").option("--skip-apps", "Skip syncing apps").option("--skip-folders", "Skip syncing folders").option("--skip-workspace-dependencies", "Skip syncing workspace dependencies").option("--include-schedules", "Include syncing schedules").option("--include-triggers", "Include syncing triggers").option("--include-users", "Include syncing users").option("--include-groups", "Include syncing groups").option("--include-settings", "Include syncing workspace settings").option("--include-key", "Include workspace encryption key").option("--skip-reencrypt-on-key-change", "When the pushed encryption key differs from the remote, do NOT re-encrypt existing remote secrets. Only safe if they are already encrypted with the new key (e.g. workspace/instance migration). Default is to re-encrypt.").option("--skip-branch-validation", "Skip git branch validation and prompts").option("--json-output", "Output results in JSON format").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string)").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which file to NOT take into account.").option("--extra-includes <patterns:file[]>", "Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy").option("--message <message:string>", "Include a message that will be added to all scripts/flows/apps updated during this push").option("--parallel <number>", "Number of changes to process in parallel").option("--repository <repo:string>", "Specify repository path (e.g., u/user/repo) when multiple repositories exist").option("--branch, --env <branch:string>", "[Deprecated: use --workspace] Override the current git branch/environment").option("--lint", "Run lint validation before pushing").option("--locks-required", "Fail if scripts or flow inline scripts that need locks have no locks").option("--auto-metadata", "Automatically regenerate stale metadata (locks and schemas) before pushing").option("--accept-overriding-permissioned-as-with-self", "Accept that items with a different permissioned_as will be updated with your own user").action(push4).command("git-deploy").hidden().description("Internal git-sync deployment-callback step (used by the git-sync hub script). Runs inside an existing clone: switches to the wm_deploy/fork branch when applicable, pulls workspace content, then commits and pushes.").option("--repository <repo:string>", "Repository resource path (e.g. u/user/repo)").option("--git-deploy-items <json:string>", "JSON array of {path_type,path,parent_path,commit_msg} being deployed").option("--use-individual-branch", "Push each deployed object to its own wm_deploy/<workspace>/<...> branch").option("--group-by-folder", "With --use-individual-branch, group deployed objects per folder branch").option("--only-create-branch", "Only create/push the deploy branch, skip pulling and committing files").option("--parent-workspace-id <id:string>", "Parent workspace id, used to root a fork-of-a-fork branch").option("--dev-workspace-label <label:string>", "Environment label of a dev workspace (dev/staging); its deploys go to that branch").option("--parent-dev-workspace-label <label:string>", "Environment label of the parent dev workspace; roots a fork-of-dev branch on it").option("--skip-secrets", "Skip syncing only secrets variables").option("--git-committer-email <email:string>", "Committer email for the deploy commit (GPG-signed repos pass the GPG key email; defaults to WM_EMAIL)").option("--git-committer-name <name:string>", "Committer name for the deploy commit (defaults to WM_USERNAME)").action(gitDeploy);
|
|
70962
70961
|
sync_default = command8;
|
|
70963
70962
|
});
|
|
70964
70963
|
|
|
@@ -86109,7 +86108,21 @@ A raw app has three logical parts:
|
|
|
86109
86108
|
|
|
86110
86109
|
### Entrypoint
|
|
86111
86110
|
|
|
86112
|
-
\`index.tsx\` is the bundling entrypoint
|
|
86111
|
+
The entrypoint is \`index.tsx\` for React and \`index.ts\` for Svelte and Vue. It is both the bundling entrypoint (the bundler is esbuild) and the **mount** entrypoint: the preview executes the bundle against an empty \`<div id="root">\` and auto-renders nothing, so the entrypoint must mount a top-level \`App\` itself. Keep the UI in \`App.tsx\` / \`App.svelte\` / \`App.vue\` and keep the entrypoint as the mount shim.
|
|
86112
|
+
|
|
86113
|
+
React (\`index.tsx\`):
|
|
86114
|
+
|
|
86115
|
+
\`\`\`tsx
|
|
86116
|
+
import React from 'react'
|
|
86117
|
+
import { createRoot } from 'react-dom/client'
|
|
86118
|
+
import App from './App'
|
|
86119
|
+
|
|
86120
|
+
createRoot(document.getElementById('root')!).render(<App />)
|
|
86121
|
+
\`\`\`
|
|
86122
|
+
|
|
86123
|
+
Svelte (\`index.ts\`): \`mount(App, { target: document.getElementById('root')! })\`. Vue (\`index.ts\`): \`createApp(App).mount('#root')\`.
|
|
86124
|
+
|
|
86125
|
+
**Never replace the entrypoint with a bare component** (\`export default function App() { ... }\` and no mount call). A component that is defined but never mounted renders a blank screen with **no error thrown** — it never executes, so nothing reaches the console or the error overlay. If an app renders blank, check that the entrypoint still mounts \`App\` into \`#root\`.
|
|
86113
86126
|
|
|
86114
86127
|
**Always begin every React file (\`.tsx\`/\`.jsx\`) that uses JSX with \`import React from 'react'\`.** esbuild uses the classic JSX transform, so \`React\` must be in scope wherever JSX appears — a missing import compiles fine but throws \`React is not defined\` at runtime, leaving a blank screen.
|
|
86115
86128
|
|