UNPKG

vite-plugin-prerelease

Version:
499 lines (481 loc) 14.7 kB
'use strict'; var MagicString = require('magic-string'); var serialize2 = require('serialize-javascript'); var cheerio = require('cheerio'); var fsp2 = require('fs/promises'); var path2 = require('path'); var vite = require('vite'); var glob = require('tiny-glob'); var dotenv = require('dotenv'); var fs = require('fs'); var module$1 = require('module'); var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var MagicString__default = /*#__PURE__*/_interopDefault(MagicString); var serialize2__default = /*#__PURE__*/_interopDefault(serialize2); var cheerio__namespace = /*#__PURE__*/_interopNamespace(cheerio); var fsp2__default = /*#__PURE__*/_interopDefault(fsp2); var path2__default = /*#__PURE__*/_interopDefault(path2); var glob__default = /*#__PURE__*/_interopDefault(glob); var fs__default = /*#__PURE__*/_interopDefault(fs); var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/node/runtime-env/index.ts var runtime_env_exports = {}; __export(runtime_env_exports, { runtimeEnv: () => runtimeEnv }); function runtimeEnv(options) { const { excludeEnvs } = options; let config; const runtimeEnvPlugin = { name: "vite:plugin-runtime-env", async configResolved(_config) { config = _config; }, transform(code, _, options2) { const { ssr } = options2 || {}; const magicString = new MagicString__default.default(code); const importMetaPattern = /import\.meta\.env(?:\.([A-Z0-9_]+))?/g; let match; while (match = importMetaPattern.exec(code)) { const start = match.index; const end = start + match[0].length; const name = match[1]; if (name && excludeEnvs.includes(name)) { continue; } const replaceCode = { ssr: ( /*js*/ `(() => { let isPreRelease = false if (global.__isPrerelease__) { isPreRelease = true } return ${serialize2__default.default(global.__env__)}?.[isPreRelease ? 'prerelease' : 'current']${name ? `.${name}` : ""} })()` ), crs: ( /*js*/ `(() => { let isPreRelease = false if (window.Cookies?.get('prerelease') === 'true') { isPreRelease = true } return window.__env__?.[isPreRelease ? 'prerelease' : 'current']${name ? `.${name}` : ""} })()` ) }; magicString.overwrite(start, end, ssr ? replaceCode.ssr : replaceCode.crs); } if (!magicString.hasChanged()) { return { code, map: null }; } if (!config.build.sourcemap) { return { code: magicString.toString(), map: null }; } return { code: magicString.toString(), map: magicString.generateMap({ hires: true }) }; } }; return [runtimeEnvPlugin]; } var init_runtime_env = __esm({ "src/node/runtime-env/index.ts"() { } }); function transformHtml(originHtml, prereleaseHtml) { if (!originHtml || !prereleaseHtml) return; const $ = cheerio__namespace.load(originHtml); const pre$ = cheerio__namespace.load(prereleaseHtml); const generateDynamicTags = ($2) => { return [ ...$2("script").filter((_, el) => Boolean($2(el).attr("src"))), ...$2("link").filter((_, el) => Boolean($2(el).attr("href"))), // legacy ...$2("script").filter((_, el) => Boolean($2(el).data("src") && $2(el).attr("id") === "vite-legacy-entry")), // log-time ...$2("script").filter((_, el) => typeof $2(el).data("log-time") !== "undefined") ]; }; const dynamicTags = generateDynamicTags($); const dynamicTagsOfPre = generateDynamicTags(pre$); dynamicTags.forEach((el) => { $(el).remove(); }); const createInsertScript = (dynamicTags2) => { return dynamicTags2.map((e) => { return { attribs: e.attribs, tag: e.tagName, children: $(e).html() }; }); }; const code = ( /* js */ ` !(function() { function insertTags(tags) { tags.forEach(({ attribs, tag, children }) => { const element = document.createElement(tag) for (const key in attribs) { element.setAttribute(key, attribs[key]) } if(children) { element.innerHTML = children } document.head.appendChild(element) }) } const isPrerelease = window.Cookies.get('prerelease') === 'true' const attrs = isPrerelease ? ${JSON.stringify(createInsertScript(dynamicTagsOfPre))} : ${JSON.stringify(createInsertScript(dynamicTags))} insertTags(attrs) })() ` ); $("body").after(`<script>${code}</script>`); return $.html().replace(/^\s*$(?:\r\n?|\n)/gm, ""); } var init_utils = __esm({ "src/node/buildtime-env/utils.ts"() { } }); // src/node/buildtime-env/index.ts var buildtime_env_exports = {}; __export(buildtime_env_exports, { buildtimeEnv: () => buildtimeEnv }); function buildtimeEnv(options) { const { prereleaseEnv, __debug } = options || {}; const definePlugin = { name: "vite:plugin-prerelease-define", apply(_, env) { return env.mode === prereleaseEnv && env.command === "build" || __debug; }, config() { return { define: { "import.meta.env.PRERELEASE": "true" } }; } }; let config; let originalHtml; let prereleaseHtml; const buildPlugin = { name: "vite:plugin-prerelease-build", enforce: "post", apply(_, env) { if (env.mode === prereleaseEnv) return false; return env.command === "build"; }, configResolved(resolvedConfig) { config = resolvedConfig; }, transformIndexHtml: { order: "post", handler(html) { originalHtml = html; } }, async closeBundle() { config.logger.info("Building prerelease..."); await vite.build({ configFile: config.configFile, mode: prereleaseEnv, base: vite.normalizePath(`${config.base}/prerelease`), build: { outDir: vite.normalizePath(`${config.build.outDir}/prerelease`) }, plugins: [ { name: "vite:plugin-prerelease-html", enforce: "post", transformIndexHtml: { order: "post", handler(html) { prereleaseHtml = html; } } } ] }); const transformedHtml = transformHtml(originalHtml, prereleaseHtml); if (transformedHtml) { await fsp2__default.default.writeFile(path2__default.default.join(config.build.outDir, "index.html"), transformedHtml); } config.logger.info("Prerelease build complete"); } }; return [definePlugin, buildPlugin]; } var init_buildtime_env = __esm({ "src/node/buildtime-env/index.ts"() { init_utils(); } }); function arraify(target) { return Array.isArray(target) ? target : [target]; } function getEnvFilesForMode(mode, envDir) { return [ /** default file */ `.env`, /** local file */ `.env.local`, /** mode file */ `.env.${mode}`, /** mode local file */ `.env.${mode}.local` ].map((file) => vite.normalizePath(path2__default.default.join(envDir, file))); } function tryStatSync(file) { try { return fs__default.default.statSync(file, { throwIfNoEntry: false }); } catch { } } function loadEnv(mode, envDir, prefixes = "VITE_") { prefixes = arraify(prefixes); const env = {}; const envFiles = getEnvFilesForMode(mode, envDir); const parsed = Object.fromEntries( envFiles.flatMap((filePath) => { var _a; if (!((_a = tryStatSync(filePath)) == null ? undefined : _a.isFile())) return []; return Object.entries(dotenv.parse(fs__default.default.readFileSync(filePath))); }) ); for (const [key, value] of Object.entries(parsed)) { if (prefixes.some((prefix) => key.startsWith(prefix))) { env[key] = value; } } return env; } function resolveEnvFromConfig(config, prereleaseEnv) { const env = { prerelease: { ...config.env, ...loadEnv(prereleaseEnv, config.envDir, config.envPrefix), // define import.meta.env.PRERELEASE PRERELEASE: true, MODE: prereleaseEnv }, current: { ...config.env, ...loadEnv(config.mode, config.envDir, config.envPrefix) } }; global.__env__ = env; return env; } async function resolveJsCookie() { const require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('astro.cjs', document.baseURI).href))); const jsCookie = await vite.transformWithEsbuild( await fsp2__default.default.readFile(path2__default.default.join(path2__default.default.dirname(require2.resolve("js-cookie")), "js.cookie.js"), "utf-8"), "" ); return jsCookie.code; } // src/node/virtual.ts var id = (name) => `virtual:prerelease-${name}`; var runtimeId = id("runtime"); var vmods = [runtimeId]; var resolvedVirtualModuleId = (virtualModuleId) => `\0${virtualModuleId}`; // src/node/index.ts async function prerelease(options) { const { mode = "runtime", excludeEnvs = [], prereleaseEnv = "production", prereleaseWidget = {}, entry, __debug = false } = options; if (process.env.NODE_ENV === prereleaseEnv || process.env.NODE_ENV === "production") { return; } let entryFile = entry || ""; let config; let env; const configPlugin = { name: "vite:plugin-prerelease-config", enforce: "pre", config() { return { ssr: { noExternal: ["vite-plugin-prerelease"] }, optimizeDeps: { exclude: [id("*")] } }; }, configResolved: { order: "pre", async handler(_config) { config = _config; if (!entryFile) { const maybeEntry = ["src/main", "src/root", "app/main", "app/root"]; for (const file of maybeEntry) { try { const files = await glob__default.default(`${file}.{ts,tsx,js,jsx}`, { cwd: config.root, filesOnly: true, absolute: true }); if (files.length) { entryFile = vite.normalizePath(files[0]); break; } } catch { } } if (!entryFile) { console.warn('\n[vite-plugin-prerelease]: Entry file not found, please specify the "entry" in the options'); } } env = resolveEnvFromConfig(config, prereleaseEnv); } }, transform: { order: "pre", handler(code, id2, options2) { if (!entryFile) return; let isEntry = false; if (entryFile instanceof RegExp && entryFile.test(id2)) { isEntry = true; } else if (new RegExp(entryFile).test(id2)) { isEntry = true; } else if (entryFile === id2) { isEntry = true; } if (isEntry && !(options2 == null ? undefined : options2.ssr)) { return { code: `import '${runtimeId}'; ${code} `, map: null }; } } }, resolveId(id2) { if (vmods.includes(id2)) { return resolvedVirtualModuleId(id2); } return null; }, async load(id2) { switch (id2) { case resolvedVirtualModuleId(runtimeId): { const jsCookie = await resolveJsCookie(); return { code: ( /*js*/ ` import { PrereleaseWidget, clientApi } from 'vite-plugin-prerelease/client' if (typeof window !== 'undefined') { ${jsCookie} window.__env__ = ${serialize2__default.default(env)} const prereleaseQuery = new URLSearchParams(window.location.search).get('prerelease') if (prereleaseQuery === 'true') { clientApi.enablePrerelease() } else if (prereleaseQuery === 'false') { clientApi.disablePrelease() } setTimeout(() => { new PrereleaseWidget(${serialize2__default.default(prereleaseWidget)}) }, 200) } ` ), map: null }; } } } }; const commonPlugins = [configPlugin]; if (mode === "runtime") { const { runtimeEnv: runtimeEnv2 } = await Promise.resolve().then(() => (init_runtime_env(), runtime_env_exports)); return [ ...commonPlugins, ...runtimeEnv2({ excludeEnvs }) ]; } else { const { buildtimeEnv: buildtimeEnv2 } = await Promise.resolve().then(() => (init_buildtime_env(), buildtime_env_exports)); return [ ...commonPlugins, ...buildtimeEnv2({ prereleaseEnv, __debug }) ]; } } // src/node/astro/index.ts function prerelease2(options) { const { prereleaseEnv = "production" } = options || {}; return { name: "vite-plugin-prerelease-integration", hooks: { "astro:config:setup": ({ injectScript, updateConfig }) => { updateConfig({ vite: { plugins: [ prerelease({ ...options, mode: "runtime", entry: "astro:scripts/page.js" }) ] } }); if (process.env.NODE_ENV === prereleaseEnv || process.env.NODE_ENV === "production") { return; } injectScript("page", ""); } } }; } exports.prerelease = prerelease2;