vike
Version:
The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.
94 lines (93 loc) • 3.97 kB
JavaScript
import '../assertEnvVite.js';
export { pluginReplaceConstantsPageContext };
import { assert } from '../../../utils/assert.js';
import { assertPosixPath } from '../../../utils/path.js';
import { normalizeId } from '../shared/normalizeId.js';
import { isViteServerSide_extraSafe } from '../shared/isViteServerSide.js';
import { getMagicString } from '../shared/getMagicString.js';
const constantsIsClientSide = [
//
'pageContext.isClientSide',
'globalContext.isClientSide',
'pageContext.globalContext.isClientSide',
];
// - See https://vike.dev/pageContext#narrowing-down
// - We cannot use [`define`](https://vite.dev/config/shared-options.html#define) because of https://github.com/rolldown/rolldown/issues/4300
// === Rolldown filter
const skipNodeModules = '/node_modules/';
const skipIrrelevant = 'Context.isClientSide';
assert(constantsIsClientSide.every((constant) => constant.endsWith(skipIrrelevant)));
const filterRolldown = {
id: {
exclude: `**${skipNodeModules}**`,
},
code: {
include: skipIrrelevant,
},
};
const filterFunction = (id, code) => {
if (id.includes(skipNodeModules))
return false;
if (!code.includes(skipIrrelevant))
return false;
return true;
};
// ===
function pluginReplaceConstantsPageContext() {
let config;
return [
{
name: 'vike:pluginReplaceConstantsPageContext',
enforce: 'post',
apply: 'build',
configResolved: {
handler(config_) {
config = config_;
},
},
transform: {
filter: filterRolldown,
handler(code, id, options) {
id = normalizeId(id);
assertPosixPath(id);
assertPosixPath(config.root);
if (!id.startsWith(config.root))
return; // skip linked dependencies
assert(filterFunction(id, code));
const isBuild = config.command === 'build';
assert(isBuild);
// Used by vike.dev
// https://github.com/vikejs/vike/blob/08a1ff55c80ddca64ca6d4417fefd45fefeb4ffb/docs/vite.config.ts#L12
// @ts-expect-error
if (config._skipVikeReplaceConstants?.(id))
return;
const { magicString, getMagicStringResult } = getMagicString(code, id);
if (constantsIsClientSide.some((c) => code.includes(c))) {
const replacement = !isViteServerSide_extraSafe(config, this.environment, options);
const regExp = getConstantRegExp(constantsIsClientSide);
magicString.replaceAll(regExp, JSON.stringify(replacement));
}
return getMagicStringResult();
},
},
},
];
}
// Copied & adapted from:
// https://github.com/rollup/plugins/blob/e1a5ef99f1578eb38a8c87563cb9651db228f3bd/packages/replace/src/index.js#L57-L67
function getConstantRegExp(constants) {
const keys = Object.values(constants).sort(longest).map(escape);
// const delimiters = ['\\b', '\\b(?!\\.)']
const delimiters = ['(?<!\\.)\\b', '\\b(?!\\.)']; // Improved version, to avoid replacing `globalContext.pageContext.isClientSide` with `globalContext.false`
const preventAssignment = false; // Let's try without it first, let's see if a user complains
const lookbehind = preventAssignment ? '(?<!\\b(?:const|let|var)\\s*)' : '';
const lookahead = preventAssignment ? '(?!\\s*=[^=])' : '';
const pattern = new RegExp(`${lookbehind}${delimiters[0]}(${keys.join('|')})${delimiters[1]}${lookahead}`, 'g');
return pattern;
}
function escape(str) {
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
}
function longest(a, b) {
return b.length - a.length;
}