Skip to content

Commit 85a6758

Browse files
committed
WIP
1 parent 6d13778 commit 85a6758

5 files changed

Lines changed: 232 additions & 93 deletions

File tree

bin/storefront-hot-proxy/live-reload-server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module.exports = function createLiveReloadServer(sslOptions) {
6060
return;
6161
}
6262

63-
console.log('Starting the SidworksDevTools hot reload server:\n');
63+
// startup summary is handled by start-hot-reload.js
6464
})();
6565

6666
compiler.hooks.done.tap('resolveServer', () => {

bin/storefront-hot-proxy/patch-webpack-config.js

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -301,14 +301,11 @@ function loadPatchedWebpackConfig(explicitProjectRoot) {
301301
if (useSassEmbedded) {
302302
try {
303303
sassImplementation = storefrontRequire('sass-embedded');
304-
console.log('[SidworksDevTools] Using sass-embedded in hot mode');
305304
} catch (_error) {
306305
try {
307306
sassImplementation = runtimeRequire('sass-embedded');
308-
console.log('[SidworksDevTools] Using sass-embedded from runtime in hot mode');
309307
} catch (_runtimeError) {
310-
console.log('[SidworksDevTools] sass-embedded not available, using sass');
311-
console.log('[SidworksDevTools] Install hint: npm --prefix vendor/shopware/storefront/Resources/app/storefront i -D sass-embedded');
308+
// sass-embedded not available, keep using sass
312309
}
313310
}
314311
}
@@ -342,7 +339,6 @@ function loadPatchedWebpackConfig(explicitProjectRoot) {
342339

343340
if (disableScss && coreConfig.entry && Object.prototype.hasOwnProperty.call(coreConfig.entry, 'hot-reloading')) {
344341
delete coreConfig.entry['hot-reloading'];
345-
console.log('[SidworksDevTools] SCSS compilation disabled (--no-scss)');
346342
}
347343

348344
if (disableJs) {
@@ -354,23 +350,18 @@ function loadPatchedWebpackConfig(explicitProjectRoot) {
354350
}
355351

356352
coreConfig.entry = nextEntry;
357-
console.log('[SidworksDevTools] JS compilation disabled (--no-js)');
358353
}
359354

360355
if (useScssSidecar) {
361356
if (coreConfig.entry && Object.prototype.hasOwnProperty.call(coreConfig.entry, 'hot-reloading')) {
362357
delete coreConfig.entry['hot-reloading'];
363358
}
364-
console.log('[SidworksDevTools] SCSS sidecar mode enabled (webpack SCSS entry disabled)');
365359
patchScssSidecarWatchBehavior(configArray);
366360
patchScssRulesToNoop(configArray);
367-
console.log('[SidworksDevTools] SCSS sidecar mode: webpack SCSS imports disabled (handled by sidecar)');
368-
console.log('[SidworksDevTools] SCSS sidecar mode: webpack ignores SCSS/SASS change events (JS rebuilds only on JS changes)');
369361
}
370362

371363
if (disableTwig && coreConfig.devServer) {
372364
delete coreConfig.devServer.watchFiles;
373-
console.log('[SidworksDevTools] Twig watch disabled (--no-twig)');
374365
}
375366

376367
const assetPort = parseInt(process.env.STOREFRONT_ASSETS_PORT || '', 10) || 9999;
@@ -416,9 +407,7 @@ function loadPatchedWebpackConfig(explicitProjectRoot) {
416407

417408
const effectiveConfigArray = coreOnlyHotMode ? [coreConfig] : configArray;
418409

419-
if (coreOnlyHotMode) {
420-
console.log('[SidworksDevTools] Core-only hot mode enabled (plugin JS compilers disabled)');
421-
}
410+
// coreOnlyHotMode is reflected in the PHP startup overview
422411

423412
if (!verboseWebpackOutput) {
424413
stripWebpackBarPlugins(effectiveConfigArray);

bin/storefront-hot-proxy/scss-sidecar.js

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,16 @@ function toScssImportPath(filePath) {
3737
return String(filePath).replace(/\\/g, '/').replace(/"/g, '\\"');
3838
}
3939

40+
const resolutionCache = new Map();
41+
4042
function resolveScssCandidate(rawPath) {
4143
const normalizedPath = path.resolve(rawPath);
44+
45+
const cached = resolutionCache.get(normalizedPath);
46+
if (cached !== undefined) {
47+
return cached;
48+
}
49+
4250
const extension = path.extname(normalizedPath);
4351
const hasResolvableExtension = ['.scss', '.sass', '.css'].includes(extension);
4452
const dirname = path.dirname(normalizedPath);
@@ -64,16 +72,44 @@ function resolveScssCandidate(rawPath) {
6472
for (const candidate of candidates) {
6573
try {
6674
if (fs.statSync(candidate).isFile()) {
75+
resolutionCache.set(normalizedPath, candidate);
6776
return candidate;
6877
}
6978
} catch (_error) {
7079
// not found
7180
}
7281
}
7382

83+
resolutionCache.set(normalizedPath, null);
7484
return null;
7585
}
7686

87+
function invalidateResolutionCacheForChangedFiles(changedFiles, projectRoot) {
88+
if (!changedFiles || changedFiles.length === 0) {
89+
return;
90+
}
91+
92+
const absolutePaths = new Set();
93+
for (const file of changedFiles) {
94+
if (typeof file !== 'string' || file === '') {
95+
continue;
96+
}
97+
98+
const abs = path.isAbsolute(file) ? file : path.resolve(projectRoot, file);
99+
absolutePaths.add(abs);
100+
}
101+
102+
if (absolutePaths.size === 0) {
103+
return;
104+
}
105+
106+
for (const [key, value] of resolutionCache) {
107+
if (absolutePaths.has(key) || (value && absolutePaths.has(value))) {
108+
resolutionCache.delete(key);
109+
}
110+
}
111+
}
112+
77113
function toWatchedFilePath(item) {
78114
if (typeof item === 'string') {
79115
return item;
@@ -131,6 +167,8 @@ function createScssSidecar(projectRoot) {
131167
const scssSourceMapEnabled = asString(process.env.SHOPWARE_STOREFRONT_SCSS_SOURCE_MAP, '1') === '1';
132168
const silenceDeprecations = asString(process.env.SHOPWARE_STOREFRONT_SASS_SILENCE_DEPRECATIONS, '1') === '1';
133169

170+
const fileContentCache = new Map();
171+
134172
const state = {
135173
subscribers: new Set(),
136174
watchpack: null,
@@ -173,22 +211,24 @@ function createScssSidecar(projectRoot) {
173211

174212
function resolveSassImplementation() {
175213
try {
176-
const embedded = storefrontRequire('sass-embedded');
177-
console.log('[SidworksDevTools] SCSS sidecar uses sass-embedded from storefront');
178-
return embedded;
214+
return storefrontRequire('sass-embedded');
179215
} catch (_error) {
180216
try {
181-
const embedded = runtimeRequire('sass-embedded');
182-
console.log('[SidworksDevTools] SCSS sidecar uses sass-embedded from runtime');
183-
return embedded;
217+
return runtimeRequire('sass-embedded');
184218
} catch (_runtimeError) {
185-
const sass = storefrontRequire('sass');
186-
console.log('[SidworksDevTools] SCSS sidecar fallback: using sass');
187-
return sass;
219+
return storefrontRequire('sass');
188220
}
189221
}
190222
}
191223

224+
function describeSassImplementation() {
225+
const info = String(state.sassImplementation?.info || '').toLowerCase();
226+
if (info.includes('sass-embedded')) {
227+
return 'sass-embedded';
228+
}
229+
return 'sass';
230+
}
231+
192232
function findTildeImport(url) {
193233
if (!url || typeof url !== 'string' || !url.startsWith('~')) {
194234
return null;
@@ -331,10 +371,7 @@ function createScssSidecar(projectRoot) {
331371
writeGeneratedThemeEntry(generatedEntryContent);
332372
state.activeEntryPath = generatedThemeEntryPath;
333373

334-
if (!state.loggedGeneratedEntryInfo) {
335-
console.log('[SidworksDevTools] SCSS sidecar uses generated entry from theme-files.json');
336-
state.loggedGeneratedEntryInfo = true;
337-
}
374+
state.loggedGeneratedEntryInfo = true;
338375

339376
return generatedThemeEntryPath;
340377
}
@@ -413,6 +450,9 @@ function createScssSidecar(projectRoot) {
413450
async function compileAndWatch(reason, changedFiles = []) {
414451
if (!state.sassImplementation) {
415452
state.sassImplementation = resolveSassImplementation();
453+
const engine = describeSassImplementation();
454+
const persistent = typeof state.sassImplementation.initAsyncCompiler === 'function' ? ', persistent' : '';
455+
log.log(`${engine}${persistent}`);
416456
}
417457

418458
const fileSummary = summarizeFiles(changedFiles);
@@ -431,6 +471,8 @@ function createScssSidecar(projectRoot) {
431471
}
432472

433473
state.compileInFlight = true;
474+
fileContentCache.clear();
475+
invalidateResolutionCacheForChangedFiles(changedFiles, rootPath);
434476
const startedAt = Date.now();
435477
log.status('RUN', `compiling (${reasonLabel})`);
436478

@@ -491,7 +533,6 @@ function createScssSidecar(projectRoot) {
491533
const sass = state.sassImplementation;
492534
if (typeof sass.initAsyncCompiler === 'function') {
493535
state.persistentCompiler = await sass.initAsyncCompiler();
494-
console.log('[SidworksDevTools] SCSS persistent compiler initialized (Dart VM kept alive)');
495536
return state.persistentCompiler;
496537
}
497538

@@ -545,7 +586,11 @@ function createScssSidecar(projectRoot) {
545586
},
546587
load(canonicalUrl) {
547588
const resolvedPath = fileURLToPath(canonicalUrl);
548-
const contents = fs.readFileSync(resolvedPath, 'utf8');
589+
let contents = fileContentCache.get(resolvedPath);
590+
if (contents === undefined) {
591+
contents = fs.readFileSync(resolvedPath, 'utf8');
592+
fileContentCache.set(resolvedPath, contents);
593+
}
549594

550595
if (resolvedPath.endsWith('.sass')) {
551596
return { contents, syntax: 'indented' };

bin/storefront-hot-proxy/start-hot-reload.js

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ const baseProxyOptions = {
102102
let scssSidecar = null;
103103
if (!disableScss && scssEngine === 'sass-cli') {
104104
scssSidecar = createScssSidecar(projectRootPath);
105-
} else if (disableScss) {
106-
console.log('[SidworksDevTools] SCSS sidecar disabled (--no-scss)');
107105
}
108106

109107
const changeFeedbackWatcher = createChangeFeedbackWatcher(projectRootPath);
@@ -219,9 +217,7 @@ const proxy = (req, res) => {
219217
};
220218

221219
if (appUrlEnv.protocol === 'https:' && !sslFilesFound) {
222-
console.error('Could not find the key and certificate files.');
223-
console.error('Make sure that the environment variables STOREFRONT_HTTPS_KEY_FILE and STOREFRONT_HTTPS_CERTIFICATE_FILE are set correctly.');
224-
console.error('If you use a TLS proxy (like in DDEV Shopware 6 setup), you can ignore this message.');
220+
console.warn(`[SidworksDevTools] ${tag('SSL', ANSI.yellow)} No certificate files found. Set STOREFRONT_HTTPS_KEY_FILE / STOREFRONT_HTTPS_CERTIFICATE_FILE or ignore if using a TLS proxy (DDEV).`);
225221
}
226222

227223
const sslOptions = proxyUrlEnv.protocol === 'https:' && skipSslCerts === false ? {
@@ -235,50 +231,44 @@ const server = createLiveReloadServer(sslOptions).catch((e) => {
235231
return createLiveReloadServer({});
236232
});
237233

238-
server.then(() => {
239-
console.log(`[SidworksDevTools] ${tag('URL')} storefront: ${colorize(appUrlEnv.origin, ANSI.green)}`);
240-
console.log(`[SidworksDevTools] ${tag('URL')} hot proxy: ${colorize(proxyUrlEnv.origin, ANSI.green)}`);
234+
if (scssSidecar) {
235+
scssSidecar.start().catch((error) => {
236+
console.error(`[SidworksDevTools] ${tag('SCSS', ANSI.red)} Failed to start sidecar: ${error.message}`);
237+
});
238+
}
239+
240+
changeFeedbackWatcher.start();
241241

242+
server.then(() => {
242243
if (proxyUrlEnv.protocol === 'https:' && skipSslCerts === false) {
243244
try {
244245
const httpsServer = nodeServerHttps.createServer(sslOptions, proxy);
245246
listenProxyServer(httpsServer, 'https');
246247
} catch (e) {
247248
console.error(e);
248-
console.error('Could not start the proxy server with the provided certificate files, falling back to http server.');
249+
console.error('Could not start proxy with certificates, falling back to HTTP.');
249250
proxyUrlEnv.protocol = 'http:';
250251
}
251252
}
252253

253254
if (proxyUrlEnv.protocol === 'http:' || skipSslCerts === true) {
254255
const httpServer = nodeServerHttp.createServer(proxy);
255-
listenProxyServer(httpServer, 'http', skipSslCerts);
256+
listenProxyServer(httpServer, 'http');
256257
}
257258

259+
const protocol = proxyUrlEnv.protocol === 'https:' ? 'HTTPS' : 'HTTP';
260+
console.log('');
261+
console.log(`[SidworksDevTools] ${colorize('Ready', ANSI.green)} (${protocol})`);
262+
console.log('');
263+
console.log(` Storefront ${colorize(appUrlEnv.origin, ANSI.cyan)}`);
264+
console.log(` Hot proxy ${colorize(proxyUrlEnv.origin, ANSI.green)}`);
258265
console.log('');
259266

260267
if (shouldOpenBrowser) {
261268
openBrowserWithUrl(`${proxyUrlEnv.origin}`);
262-
return;
263269
}
264-
265-
console.log(`[SidworksDevTools] ${tag('OPEN', ANSI.yellow)} auto-open disabled. Open manually: ${proxyUrlEnv.origin}`);
266270
});
267271

268-
if (scssSidecar) {
269-
scssSidecar.start().then((started) => {
270-
if (started) {
271-
console.log('[SidworksDevTools] SCSS sidecar active (sass-cli mode)');
272-
}
273-
}).catch((error) => {
274-
console.error('[SidworksDevTools] Failed to start SCSS sidecar:', error.message);
275-
});
276-
}
277-
278-
if (changeFeedbackWatcher.start()) {
279-
console.log('[SidworksDevTools] JS/Twig change feedback watcher active');
280-
}
281-
282272
function cleanup() {
283273
if (scssSidecar) {
284274
scssSidecar.close();
@@ -353,24 +343,16 @@ function parseUrlOrNull(value) {
353343
}
354344
}
355345

356-
function listenProxyServer(server, protocol, skipSslMessage = false) {
346+
function listenProxyServer(server, protocol) {
357347
server.on('error', (error) => {
358348
if (error.code === 'EADDRINUSE') {
359-
console.error(`Proxy port ${proxyPort} is already in use.`);
360-
console.error('Stop the existing watcher process or use a different STOREFRONT_PROXY_PORT.');
349+
console.error(`[SidworksDevTools] Port ${proxyPort} is already in use. Stop the existing watcher or use a different STOREFRONT_PROXY_PORT.`);
361350
process.exit(1);
362351
}
363352

364-
console.error(`Unable to start ${protocol} proxy server:`, error);
353+
console.error(`[SidworksDevTools] Unable to start ${protocol} proxy server:`, error);
365354
process.exit(1);
366355
});
367356

368-
server.listen(proxyPort, () => {
369-
if (protocol === 'https') {
370-
console.log(`[SidworksDevTools] ${tag('PROXY')} using HTTPS with SSL certificate files.`);
371-
return;
372-
}
373-
374-
console.log(`[SidworksDevTools] ${tag('PROXY')} using HTTP${skipSslMessage ? ' (SSL certificates are skipped).' : '.'}`);
375-
});
357+
server.listen(proxyPort);
376358
}

0 commit comments

Comments
 (0)