@@ -3,7 +3,7 @@ import { existsSync, readFileSync, realpathSync, readdirSync, lstatSync, statSyn
33import { pathToFileURL } from "node:url" ;
44import { urlToRelativeUrl , registerFileLifecycle , lookupPackageDirectory , readPackageAtOrNull , generateContentFrame , errorToHTML , DATA_URL , CONTENT_TYPE , normalizeImportMap , composeTwoImportMaps , resolveImport , JS_QUOTES , urlToExtension , urlToBasename , applyNodeEsmResolution , URL_META , readCustomConditionsFromProcessArgs , urlIsOrIsInsideOf , collectFiles , registerDirectoryLifecycle , readEntryStatSync , applyFileSystemMagicResolution , getExtensionsToTry , urlToFilename , asUrlWithoutSearch , ensurePathnameTrailingSlash , compareFileUrls , setUrlExtension , createDetailedMessage , stringifyUrlSite , injectQueryParamsIntoSpecifier , isSpecifierForNodeBuiltin , injectQueryParams , urlToFileSystemPath , writeFileSync , moveUrl , ensureWindowsDriveLetter , validateResponseIntegrity , setUrlFilename , getCallerPosition , asSpecifierWithoutSearch , bufferToEtag , isFileSystemPath , urlToPathname , setUrlBasename , createLogger , normalizeUrl , ANSI , RUNTIME_COMPAT , formatError , assertAndNormalizeDirectoryUrl , createTaskLog } from "./jsenv_core_packages.js" ;
55import { createPluginsController } from "@jsenv/server/src/plugins_controller.js" ;
6- import { parseHtml , injectJsenvScript , stringifyHtmlAst , parseCssUrls , getHtmlNodeAttribute , getHtmlNodePosition , getHtmlNodeAttributePosition , setHtmlNodeAttributes , parseSrcSet , getUrlForContentInsideHtml , removeHtmlNodeText , setHtmlNodeText , getHtmlNodeText , analyzeScriptNode , visitHtmlNodes , parseJsUrls , getUrlForContentInsideJs , applyBabelPlugins , visitJsAst , getImportMetaPropertyName , visitJsAstUntil , analyzeLinkNode , injectHtmlNodeAsEarlyAsPossible , createHtmlNode , generateUrlForInlineContent , parseJsWithAcorn } from "@jsenv/ast" ;
6+ import { parseHtml , injectJsenvScript , stringifyHtmlAst , parseCssUrls , getHtmlNodeAttribute , getHtmlNodePosition , getHtmlNodeAttributePosition , setHtmlNodeAttributes , parseSrcSet , getUrlForContentInsideHtml , removeHtmlNodeText , setHtmlNodeText , getHtmlNodeText , analyzeScriptNode , visitHtmlNodes , parseJsUrls , getUrlForContentInsideJs , renderCssTemplateLiteral , applyBabelPlugins , visitJsAst , getImportMetaPropertyName , visitJsAstUntil , analyzeLinkNode , injectHtmlNodeAsEarlyAsPossible , createHtmlNode , generateUrlForInlineContent , parseJsWithAcorn } from "@jsenv/ast" ;
77import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor" ;
88import { jsenvPluginTranspilation } from "@jsenv/plugin-transpilation" ;
99import { createMagicSource , composeTwoSourcemaps , generateSourcemapFileUrl , generateSourcemapDataUrl , SOURCEMAP } from "@jsenv/sourcemap" ;
@@ -2369,9 +2369,17 @@ const parseAndTransformJsReferences = async (
23692369
23702370 sequentialActions . push ( async ( ) => {
23712371 await inlineUrlInfo . cook ( ) ;
2372- const replacement = JS_QUOTES . escapeSpecialChars ( inlineUrlInfo . content , {
2373- quote,
2374- } ) ;
2372+ const { substitutions } = inlineReferenceInfo ;
2373+ const replacement = substitutions
2374+ ? // the expressions the template holds take their placeholder's place
2375+ // back; a template literal is written whatever the runtime supports,
2376+ // transpilation runs after and lowers it when it has to
2377+ renderCssTemplateLiteral ( inlineUrlInfo . content , substitutions )
2378+ : JS_QUOTES . escapeSpecialChars ( inlineUrlInfo . content , { quote } ) ;
2379+ if ( replacement === null ) {
2380+ // a placeholder did not survive: the source stays as it was written
2381+ return ;
2382+ }
23752383 magicSource . replace ( {
23762384 start : inlineReferenceInfo . start ,
23772385 end : inlineReferenceInfo . end ,
@@ -6133,6 +6141,12 @@ const jsenvPluginNodeRuntime = ({ runtimeCompat }) => {
61336141 * import.meta.css = css;
61346142 * ```
61356143 *
6144+ * "jsenv:js_reference_analysis" reads the css assigned here as an inline css and
6145+ * sends it through the css pipeline: transpilation, url() resolution, minification,
6146+ * comments. A "${}" standing where a css value stands is swapped for a placeholder
6147+ * and put back afterwards; anywhere else it makes the template unreadable and the
6148+ * css is shipped exactly as written, with everything the pipeline does lost.
6149+ *
61366150 */
61376151
61386152
@@ -11660,7 +11674,17 @@ const devServerPluginServeSourceFiles = ({
1166011674 // so it is derived from the url and cooked first.
1166111675 const inlineParentUrl = getInlineContentParentUrl ( requestedUrl ) ;
1166211676 if ( inlineParentUrl ) {
11663- if ( ! kitchen . graph . getUrlInfo ( inlineParentUrl ) ) {
11677+ const inlineParentUrlInfo =
11678+ kitchen . graph . getUrlInfo ( inlineParentUrl ) ;
11679+ // A parent cooked before the file changed still holds the
11680+ // references it had then; the inline content is as fresh as its
11681+ // parent, so the parent is cooked again before being asked.
11682+ if (
11683+ ! inlineParentUrlInfo ||
11684+ inlineParentUrlInfo . content === undefined ||
11685+ ! inlineParentUrlInfo . contentFinalized ||
11686+ ! inlineParentUrlInfo . isValid ( )
11687+ ) {
1166411688 const rootUrlInfo = kitchen . graph . rootUrlInfo ;
1166511689 const inlineParentWebUrl = WEB_URL_CONVERTER . asWebUrl (
1166611690 inlineParentUrl ,
@@ -11684,6 +11708,16 @@ const devServerPluginServeSourceFiles = ({
1168411708 request . resource ,
1168511709 inlineParentUrl ,
1168611710 ) ;
11711+ if ( ! reference ) {
11712+ // The parent does not hold that inline content: the script was
11713+ // edited out of the html. What the graph kept under this url is
11714+ // what the parent used to say, it must not be served.
11715+ return {
11716+ url : requestedUrl ,
11717+ status : 404 ,
11718+ statusText : "no inline content at this position" ,
11719+ } ;
11720+ }
1168711721 }
1168811722 }
1168911723 if ( reference ) {
0 commit comments