From 5e28022ebdb84b1a6294843ecbda9bf9d553019f Mon Sep 17 00:00:00 2001 From: Alice Pote Date: Wed, 25 Oct 2023 10:20:43 -0400 Subject: [PATCH] fix(www): fix an inconsistency between www builds This fixes a bug where subsequent `www` builds would not always produce working output. In particular, prior to this change a 'clean' `www` build (i.e one done after deleting all previous output) would produce a working build but subsequent builds would not. This had to do with an optimization that Stencil attempts to do during the `www` build where it will attempt to inline the JS code for the main entry point into the `index.html` that it produces. As part of doing this it needs to rewrite some relative paths for any module specifiers that are part of that entry point, since the HTML file is found at `www/index.html` while the JS entry point will be typically found at `www/build/project-name.js`. Thus if that entry point has an import like `import foo from './bar.js'` that will need to be rewritten to `import foo from '/build/bar.js'` in order for the import to resolve once its inlined into the HTML. This inlining optimization was previously broken because the path rewrite code did not account for the presence of more than one instance of a given module specifier in the soon-to-be-inlined code. However, by default we have both `import` and `export` declarations in that code, so the inlined code would end up non-functional. To give an example, the problematic excerpt of the inlined code would look typically like this: ```js import { p as e, b as t } from "/build/p-71aeae62.js"; export { s as setNonce } from "./p-71aeae62.js"; ``` so the first `import` declaration is being correctly rewritten to begin with `/build/` but the `export` declaration is not. The code should look like this: ```js import { p as e, b as t } from "/build/p-71aeae62.js"; export { s as setNonce } from "/build/p-71aeae62.js"; ``` This commit fixes the issue by transforming all instances of a given module specifier in the text, and additionally adds a regression test that tests for this specific case. --- src/compiler/html/html-utils.ts | 9 +- src/compiler/html/inline-esm-import.ts | 107 +++++++++++++----- .../html/test/update-esm-import-paths.spec.ts | 30 ++++- 3 files changed, 112 insertions(+), 34 deletions(-) diff --git a/src/compiler/html/html-utils.ts b/src/compiler/html/html-utils.ts index 9fc41dbc6c8..ddf66a8a09e 100644 --- a/src/compiler/html/html-utils.ts +++ b/src/compiler/html/html-utils.ts @@ -2,7 +2,14 @@ import { join, relative } from 'path'; import type * as d from '../../declarations'; -export const getAbsoluteBuildDir = (outputTarget: d.OutputTargetWww) => { +/** + * Get the path to the build directory where files written for the `www` output + * target should be written. + * + * @param outputTarget a www output target of interest + * @returns a path to the build directory for that output target + */ +export const getAbsoluteBuildDir = (outputTarget: d.OutputTargetWww): string => { const relativeBuildDir = relative(outputTarget.dir, outputTarget.buildDir); return join('/', relativeBuildDir) + '/'; }; diff --git a/src/compiler/html/inline-esm-import.ts b/src/compiler/html/inline-esm-import.ts index 5f91a825525..afbca3043a9 100644 --- a/src/compiler/html/inline-esm-import.ts +++ b/src/compiler/html/inline-esm-import.ts @@ -7,12 +7,30 @@ import { generateHashedCopy } from '../output-targets/copy/hashed-copy'; import { getAbsoluteBuildDir } from './html-utils'; import { injectModulePreloads } from './inject-module-preloads'; +/** + * Attempt to optimize an ESM import of the main entry point for a `www` build + * by inlining the imported script within the supplied HTML document, if + * possible. + * + * This will only do this for a `