Skip to content

Commit 04da311

Browse files
committed
fix(click to component): use vite to resolve path
1 parent ef49a82 commit 04da311

File tree

8 files changed

+95
-43
lines changed

8 files changed

+95
-43
lines changed

.changeset/six-cars-juggle.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@builder.io/qwik': patch
3+
---
4+
5+
fix: Click-to-Component is now more reliable across platforms

packages/qwik/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"ignore": "5.3.1",
3636
"image-size": "1.2.1",
3737
"kleur": "4.1.5",
38+
"launch-editor": "^2.11.1",
3839
"ts-morph": "23.0.0"
3940
},
4041
"engines": {

packages/qwik/src/optimizer/src/plugins/click-to-component.html

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -136,34 +136,24 @@
136136
const target = findContainer(event.target);
137137
if (target) {
138138
event.preventDefault();
139+
event.stopPropagation();
139140
const inspectUrl = target.getAttribute(inspectAttribute);
140141
if (inspectUrl !== 'false') {
141142
body.style.setProperty('cursor', 'progress');
142-
qwikOpenInEditor(inspectUrl);
143+
const match = inspectUrl.match(/^(.*?)(:\d+(:\d+)?)?$/);
144+
if (match) {
145+
const [, filePath, location] = match;
146+
fetch(`${filePath}?editor${location}`).then(() => {
147+
body.style.removeProperty('cursor');
148+
});
149+
}
143150
}
144151
}
145152
}
146153
},
147154
{ capture: true }
148155
);
149156

150-
globalThis.qwikOpenInEditor = function (path) {
151-
const isWindows = navigator.platform.includes('Win');
152-
const resolvedURL = new URL(path, isWindows ? origin : srcDir);
153-
let filePath =
154-
resolvedURL.protocol === 'file:' && resolvedURL.pathname.startsWith('/')
155-
? resolvedURL.pathname.slice(1)
156-
: resolvedURL.pathname.startsWith('/@fs/')
157-
? resolvedURL.pathname.slice(isWindows ? 5 : 4)
158-
: resolvedURL.pathname;
159-
if (filePath.startsWith('/src/')) {
160-
const prefix = isWindows ? srcDir : srcDir.replace('http://local.local', '');
161-
filePath = prefix + filePath.slice(4);
162-
}
163-
const params = new URLSearchParams();
164-
params.set('file', filePath);
165-
fetch('/__open-in-editor?' + params.toString());
166-
};
167157
document.addEventListener(
168158
'contextmenu',
169159
(event) => {

packages/qwik/src/optimizer/src/plugins/plugin.ts

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
1-
/* eslint-disable no-console */
2-
import type { Rollup, Plugin, ViteDevServer, HmrContext } from 'vite';
1+
import type { ManualChunksOption } from 'rollup';
2+
import type { HmrContext, Plugin, Rollup, ViteDevServer } from 'vite';
3+
import type { BundleGraphAdder } from '..';
34
import { hashCode } from '../../../core/util/hash_code';
45
import { generateManifestFromBundles, getValidManifest } from '../manifest';
56
import { createOptimizer } from '../optimizer';
67
import type {
78
Diagnostic,
89
EntryStrategy,
910
GlobalInjections,
10-
SegmentAnalysis,
1111
Optimizer,
1212
OptimizerOptions,
1313
OptimizerSystem,
1414
QwikManifest,
15+
SegmentAnalysis,
16+
ServerQwikManifest,
17+
SmartEntryStrategy,
1518
TransformModule,
1619
TransformModuleInput,
1720
TransformModulesOptions,
1821
TransformOutput,
19-
SmartEntryStrategy,
20-
ServerQwikManifest,
2122
} from '../types';
23+
import { convertManifestToBundleGraph } from './bundle-graph';
2224
import { createLinter, type QwikLinter } from './eslint-plugin';
2325
import { isWin, parseId } from './vite-utils';
24-
import type { BundleGraphAdder } from '..';
25-
import { convertManifestToBundleGraph } from './bundle-graph';
26-
import type { ManualChunksOption } from 'rollup';
2726

2827
const REG_CTX_NAME = ['server'];
2928

@@ -427,6 +426,7 @@ export function createQwikPlugin(optimizerOptions: OptimizerOptions = {}) {
427426
};
428427

429428
let resolveIdCount = 0;
429+
let doNotEdit = false;
430430
/**
431431
* This resolves virtual names and QRL segments/entries. All the rest falls through. We must
432432
* always return a value for QRL segments because they don't exist on disk.
@@ -445,6 +445,35 @@ export function createQwikPlugin(optimizerOptions: OptimizerOptions = {}) {
445445
if (id.startsWith('\0')) {
446446
return;
447447
}
448+
449+
// Intercept requests to open in editor
450+
const editMatch = devServer && /^(.*)\?editor(:(\d+)(:\d+)?)?$/.exec(id);
451+
if (editMatch) {
452+
// Throttle so we don't open multiple times on re-resolve
453+
if (!doNotEdit) {
454+
doNotEdit = true;
455+
setTimeout(() => (doNotEdit = false), 500);
456+
457+
const [, origId, location] = editMatch;
458+
// Find the actual file on disk by asking vite to resolve it
459+
const resolved = await ctx.resolve(origId, importerId);
460+
if (resolved) {
461+
const file = devServer!.moduleGraph.getModuleById(resolved.id)?.file;
462+
if (file) {
463+
const path = `${file}${location}`;
464+
try {
465+
console.warn(`Opening in editor: ${path}`);
466+
const launchEditor = (await import('launch-editor')).default;
467+
launchEditor(path);
468+
} catch (e: any) {
469+
console.error(`Failed to open editor: ${e.message}`);
470+
}
471+
}
472+
}
473+
}
474+
return { id: `\0editor` };
475+
}
476+
448477
const count = resolveIdCount++;
449478
const isServer = getIsServer(resolveOpts);
450479
debug(`resolveId(${count})`, `begin ${id} | ${isServer ? 'server' : 'client'} | ${importerId}`);
@@ -577,6 +606,10 @@ export function createQwikPlugin(optimizerOptions: OptimizerOptions = {}) {
577606
id: string,
578607
loadOpts?: Parameters<Extract<Plugin['load'], Function>>[1]
579608
): Promise<Rollup.LoadResult> => {
609+
if (id === '\0editor') {
610+
// This doesn't get used, but we need to return something
611+
return '"opening in editor"';
612+
}
580613
if (id.startsWith('\0') || id.startsWith('/@fs/')) {
581614
return;
582615
}
@@ -850,11 +883,13 @@ export function createQwikPlugin(optimizerOptions: OptimizerOptions = {}) {
850883

851884
const debug = (...str: any[]) => {
852885
if (opts.debug) {
886+
// eslint-disable-next-line no-console
853887
console.debug(`[QWIK PLUGIN: ${id}]`, ...str);
854888
}
855889
};
856890

857891
const log = (...str: any[]) => {
892+
// eslint-disable-next-line no-console
858893
console.log(`[QWIK PLUGIN: ${id}]`, ...str);
859894
};
860895

packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ const shouldSsrRender = (req: IncomingMessage, url: URL) => {
391391
if (pathname.includes('__open-in-editor')) {
392392
return false;
393393
}
394+
if (pathname.includes('?editor:')) {
395+
return false;
396+
}
394397
if (url.searchParams.has('html-proxy')) {
395398
return false;
396399
}

pnpm-lock.yaml

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
packages:
2-
- 'packages/*'
3-
- 'e2e/*'
4-
# - 'starters/adapter/*'
5-
# - 'starters/features/*'
2+
- packages/*
3+
- e2e/*
4+
5+
autoInstallPeers: false
6+
7+
engineStrict: true
68

79
onlyBuiltDependencies:
810
- '@parcel/watcher'
911
- '@tailwindcss/oxide'
10-
- 'esbuild'
11-
- 'netlify-cli'
12-
- 'puppeteer'
13-
- 'sharp'
14-
- 'simple-git-hooks'
15-
- 'unix-dgram'
16-
- 'workerd'
12+
- esbuild
13+
- netlify-cli
14+
- puppeteer
15+
- sharp
16+
- simple-git-hooks
17+
- unix-dgram
18+
- workerd
1719

1820
overrides:
19-
'typescript': '5.4.5'
20-
'vfile': '6.0.3'
21+
typescript: 5.4.5
22+
vfile: 6.0.3
2123

2224
patchedDependencies:
23-
24-
25+
26+
2527

26-
engineStrict: true
2728
shellEmulator: true
28-
autoInstallPeers: false

scripts/submodule-optimizer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export async function submoduleOptimizer(config: BuildConfig) {
3333
external: [
3434
/* no Node.js built-in externals allowed! */
3535
'espree',
36+
'launch-editor',
3637
],
3738
};
3839

0 commit comments

Comments
 (0)