vite-plugin-prerelease
Version:
vite plugin prerelease
223 lines (213 loc) • 6.01 kB
JavaScript
import serialize from 'serialize-javascript';
import glob from 'tiny-glob';
import { normalizePath, transformWithEsbuild } from 'vite';
import { parse } from 'dotenv';
import fs from 'node:fs';
import path2 from 'node:path';
import fsp from 'node:fs/promises';
import { createRequire } from 'node:module';
// src/node/index.ts
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) => normalizePath(path2.join(envDir, file)));
}
function tryStatSync(file) {
try {
return fs.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(parse(fs.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 = createRequire(import.meta.url);
const jsCookie = await transformWithEsbuild(
await fsp.readFile(path2.join(path2.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(`${file}.{ts,tsx,js,jsx}`, {
cwd: config.root,
filesOnly: true,
absolute: true
});
if (files.length) {
entryFile = 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__ = ${serialize(env)}
const prereleaseQuery = new URLSearchParams(window.location.search).get('prerelease')
if (prereleaseQuery === 'true') {
clientApi.enablePrerelease()
} else if (prereleaseQuery === 'false') {
clientApi.disablePrelease()
}
setTimeout(() => {
new PrereleaseWidget(${serialize(prereleaseWidget)})
}, 200)
}
`
),
map: null
};
}
}
}
};
const commonPlugins = [configPlugin];
if (mode === "runtime") {
const { runtimeEnv } = await import('./runtime-env-TMVJGZBE.js');
return [
...commonPlugins,
...runtimeEnv({
excludeEnvs
})
];
} else {
const { buildtimeEnv } = await import('./buildtime-env-5ASF35UA.js');
return [
...commonPlugins,
...buildtimeEnv({
prereleaseEnv,
__debug
})
];
}
}
export { prerelease };