diff --git a/lib/cmd/vite/generate-bootstrap.js b/lib/cmd/vite/generate-bootstrap.js index 1496fec..22a0385 100644 --- a/lib/cmd/vite/generate-bootstrap.js +++ b/lib/cmd/vite/generate-bootstrap.js @@ -4,6 +4,7 @@ const fs = require('fs-extra'); const path = require('path'); const { globSync } = require('glob'); const { getConfigValue } = require('../../config-file-helpers'); +const { generateViteEnvInit } = require('./generate-env-init'); const CWD = process.cwd(); const CLAY_DIR = path.join(CWD, '.clay'); @@ -106,6 +107,8 @@ mountComponentModules().catch(console.error); * @returns {Promise} absolute path to the written bootstrap file */ async function generateViteBootstrap() { + await generateViteEnvInit(); + const clientFiles = [ ...globSync(path.join(CWD, 'components', '**', 'client.js')), ...globSync(path.join(CWD, 'layouts', '**', 'client.js')), @@ -152,6 +155,8 @@ ${stickyListeners} ? "import './_globals-init.js';\n" : '// no global/js — skipping _globals-init\n'; + const envInitImport = "import './_env-init.js';\n"; + // Clay-kiln's preloader does `Object.keys(window.modules)` to find // component model.js / kiln.js registrations that Browserify's megabundler // assigns there at page load. Under Vite there is no Browserify runtime, @@ -174,6 +179,7 @@ ${stickyListeners} '// present on the current page — keeping initial parse cost low.', '', kilnCompatStub, + envInitImport, globalsImport, stickyShimBlock, 'const _clayClientModules = {', diff --git a/lib/cmd/vite/generate-env-init.js b/lib/cmd/vite/generate-env-init.js new file mode 100644 index 0000000..61f9021 --- /dev/null +++ b/lib/cmd/vite/generate-env-init.js @@ -0,0 +1,56 @@ +'use strict'; + +const fs = require('fs-extra'); +const path = require('path'); + +const CWD = process.cwd(); +const CLAY_DIR = path.join(CWD, '.clay'); +const ENV_INIT_FILE = path.join(CLAY_DIR, '_env-init.js'); + +/** + * Generate .clay/_env-init.js — runtime hydration for window.process.env. + * + * Why: + * - Universal modules can be evaluated before late env injection in some + * browser paths under ESM (especially edit-mode/kiln startup), and any + * top-level `const X = process.env.X` captures undefined permanently. + * - Hydrating window.process.env in a dedicated side-effect module imported + * first by Vite entries ensures env is present before those modules run. + * + * Sources (in priority order): + * 1) window.kiln.preloadData._envVars (authoritative edit-mode payload from amphora-html) + * 2) existing window.process.env (if already injected by any earlier script) + * + * @returns {Promise} absolute path to the generated file + */ +async function generateViteEnvInit() { + const content = [ + '// AUTO-GENERATED — clay vite env init (do not edit)', + `// ${new Date().toISOString()}`, + ';(function clayViteEnvInit() {', + ' if (typeof window === "undefined") return;', + '', + ' var fromKiln = window.kiln && window.kiln.preloadData && window.kiln.preloadData._envVars;', + ' var existing = window.process && window.process.env;', + '', + ' var source = (fromKiln && typeof fromKiln === "object")', + ' ? fromKiln', + ' : ((existing && typeof existing === "object") ? existing : {});', + '', + ' window.process = window.process || {};', + ' window.process.env = Object.assign({}, source, window.process.env || {});', + '}());', + '', + ].join('\n'); + + await fs.ensureDir(CLAY_DIR); + await fs.writeFile(ENV_INIT_FILE, content, 'utf8'); + + return ENV_INIT_FILE; +} + +module.exports = { + generateViteEnvInit, + ENV_INIT_FILE, +}; + diff --git a/lib/cmd/vite/generate-kiln-edit.js b/lib/cmd/vite/generate-kiln-edit.js index 5bb16fc..7b2f65f 100644 --- a/lib/cmd/vite/generate-kiln-edit.js +++ b/lib/cmd/vite/generate-kiln-edit.js @@ -3,6 +3,7 @@ const fs = require('fs-extra'); const path = require('path'); const { globSync } = require('glob'); +const { generateViteEnvInit } = require('./generate-env-init'); const CWD = process.cwd(); const CLAY_DIR = path.join(CWD, '.clay'); @@ -27,6 +28,8 @@ const KILN_EDIT_ENTRY_KEY = '.clay/vite-kiln-edit-init'; * @returns {Promise} absolute path to the generated file */ async function generateViteKilnEditEntry() { + await generateViteEnvInit(); + const modelFiles = [ ...globSync(path.join(CWD, 'components', '**', 'model.js')), ...globSync(path.join(CWD, 'layouts', '**', 'model.js')), @@ -54,6 +57,7 @@ async function generateViteKilnEditEntry() { // Use namespace imports (import * as) so both CJS modules (which @rollup/plugin-commonjs // gives a namespace object with a .default property) and ESM modules work uniformly. // Then resolve the actual export via _resolveDefault() at runtime. + lines.push('import \'./_env-init.js\';'); modelFiles.forEach((f, i) => lines.push(`import * as _m${i} from ${JSON.stringify(toRel(f))};`)); kilnjsFiles.forEach((f, i) => lines.push(`import * as _k${i} from ${JSON.stringify(toRel(f))};`)); if (hasKilnPlugin) {