rasengan
Version:
The modern React Framework
175 lines (174 loc) • 6.8 kB
JavaScript
import path, { resolve } from 'path';
import fs from 'fs';
import { loadModuleSSR } from '../config/utils/load-modules.js';
import { resolveBuildOptions } from '../../server.js';
import { renderIndexHTML } from '../../server/build/rendering.js';
function loadRasenganGlobal() {
return {
name: 'vite-plugin-rasengan-config',
async config(_, { command }) {
if (command !== 'build')
return;
const packageJsonPath = resolve(process.cwd(), 'package.json');
if (!fs.existsSync(packageJsonPath)) {
throw new Error(`Package.json file not found at: ${packageJsonPath}`);
}
const packageJsonRaw = fs.readFileSync(packageJsonPath, {
encoding: 'utf-8',
});
const packageJson = JSON.parse(packageJsonRaw);
const rasenganConfig = {
version: packageJson.version,
ssr: true,
};
// Inject the configuration as a global constant
return {
define: {
['Rasengan']: JSON.stringify(rasenganConfig),
},
};
},
apply: 'build',
};
}
function rasenganConfigPlugin() {
const virtualModuleId = 'virtual:rasengan-config';
const resolvedVirtualModuleId = '\0' + virtualModuleId;
return {
name: 'vite-plugin-rasengan-config',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
async load(id) {
if (id === resolvedVirtualModuleId) {
// if (command !== "build") return;
const configPath = resolve(process.cwd(), 'rasengan.config.js');
if (!fs.existsSync(configPath)) {
throw new Error(`Configuration file not found at: ${configPath}`);
}
const rasenganConfig = await (await loadModuleSSR(configPath)).default;
const partialConfig = {
server: rasenganConfig.server ?? {},
redirects: rasenganConfig.redirects
? await rasenganConfig.redirects()
: [],
};
return `
export const __RASENGAN_CONFIG__ = ${JSON.stringify(partialConfig)};
`;
}
},
};
}
function buildOutputInformation() {
const virtualModuleId = 'virtual:rasengan-build-info';
const resolvedVirtualModuleId = '\0' + virtualModuleId;
return {
name: 'vite-plugin-rasengan-build-info',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
async load(id) {
if (id === resolvedVirtualModuleId) {
return `
export const resolveBuildOptions = (buildPath) => {
return {
buildDirectory: buildPath,
manifestPathDirectory: 'client/.vite',
assetPathDirectory: 'client/assets',
entryServerPath: 'server/entry.server.js',
};
};
`;
}
},
};
}
export const Adapters = {
VERCEL: 'vercel',
DEFAULT: '',
};
export function rasengan({ adapter = { name: Adapters.DEFAULT, prepare: async () => { } }, }) {
let config;
let viteConfig;
const buildOptions = resolveBuildOptions({});
return {
name: 'vite-plugin-rasengan',
async config() {
// load rasengan.config.js
const configPath = resolve(process.cwd(), 'rasengan.config.js');
if (!fs.existsSync(configPath)) {
throw new Error(`Configuration file not found at: ${configPath}`);
}
const rasenganConfigHandler = await (await loadModuleSSR(configPath)).default;
config = await rasenganConfigHandler();
},
async load(id) {
if (id === 'virtual:rasengan-config') {
return `
export const __RASENGAN_CONFIG__ = ${JSON.stringify(config)};
`;
}
},
configResolved(resolvedConfig) {
viteConfig = resolvedConfig;
},
async writeBundle(_) {
const modulePaths = ['template.jsx', 'template.tsx'].map((file) => {
return path.posix.join(process.cwd(), 'src', file);
});
const modulePath = modulePaths.find((modulePath) => {
return fs.existsSync(modulePath);
});
const module = await this.load({ id: modulePath });
// SPA mode only
if (!config.ssr) {
// Generate the template.js file into the dist/assets
fs.writeFileSync(path.posix.join(process.cwd(), buildOptions.buildDirectory, buildOptions.assetPathDirectory, 'template.js'), module.code, 'utf-8');
}
},
async closeBundle() {
// We check here if the environment is client has been built because it's the
// last environment to be built in the Vite build process
if (this.environment.name === 'client') {
// Check if SPA mode is enabled
if (!config.ssr) {
// Load the template.js file
const templatePath = path.posix.join(process.cwd(), buildOptions.buildDirectory, buildOptions.assetPathDirectory, 'template.js');
const Template = (await import(templatePath)).default;
// Render the index.html file
await renderIndexHTML(Template, {
rootPath: process.cwd(),
config,
});
}
// Generate a config.json file into the dist/client/assets or dist/assets
const minimizedConfig = {
buildOptions,
ssr: config.ssr,
redirects: await config.redirects(),
};
fs.writeFileSync(path.posix.join(process.cwd(), buildOptions.buildDirectory, config.ssr ? buildOptions.clientPathDirectory : '', buildOptions.assetPathDirectory, 'config.json'), JSON.stringify(minimizedConfig), 'utf-8');
// Prepare the app for deployment
await prepareToDeploy(adapter);
}
},
apply: 'build',
};
}
const prepareToDeploy = async (adapter) => {
// Preparing app for deployment
switch (adapter.name) {
case Adapters.VERCEL: {
await adapter.prepare();
break;
}
default:
break;
}
};
export const plugins = [loadRasenganGlobal()];