@farmfe/core
Version:
Farm is a extremely fast web build tool written in Rust. Farm can start a project in milliseconds and perform HMR within 10ms, making it much faster than similar tools like webpack and vite.
371 lines • 12 kB
JavaScript
import path from 'node:path';
// import path from 'node:path';
import * as querystring from 'node:querystring';
import fse from 'fs-extra';
import { VITE_ADAPTER_VIRTUAL_MODULE } from './constants.js';
export function convertEnforceToPriority(value) {
const defaultPriority = 100;
const enforceToPriority = {
pre: 101,
post: 98
};
return enforceToPriority[value] !== undefined
? enforceToPriority[value]
: defaultPriority;
}
export function convertWatchEventChange(value) {
const watchEventChange = {
Added: 'create',
Updated: 'update',
Removed: 'delete'
};
return watchEventChange[value];
}
export function getContentValue(content) {
return encodeStr(typeof content === 'string' ? content : content.code);
}
export function isString(variable) {
return typeof variable === 'string';
}
export function isObject(variable) {
return typeof variable === 'object' && variable !== null;
}
export function customParseQueryString(url) {
if (!url) {
return [];
}
const queryString = url.split('?')[1];
const parsedParams = querystring.parse(queryString);
const paramsArray = [];
for (const key in parsedParams) {
paramsArray.push([key, parsedParams[key]]);
}
return paramsArray;
}
export const VITE_PLUGIN_DEFAULT_MODULE_TYPE = 'VITE_PLUGIN_DEFAULT_MODULE_TYPE';
export const CSS_LANGS_RES = [
[/\.(less)(?:$|\?)/, 'less'],
[/\.(scss|sass)(?:$|\?)/, 'sass'],
[/\.(styl|stylus)(?:$|\?)/, 'stylus'],
[/\.(css)(?:$|\?)/, 'css']
];
export const JS_LANGS_RES = [
[/\.(js|mjs|cjs|)(?:$|\?)/, 'js'],
// jsx
[/\.(jsx)(?:$|\?)/, 'jsx'],
// ts
[/\.(ts|cts|mts)(?:$|\?)/, 'ts'],
// tsx
[/\.(tsx)(?:$|\?)/, 'tsx']
];
export const DEFAULT_FILTERS = ['!node_modules'];
// farm css modules query
export const FARM_CSS_MODULES_SUFFIX = /(?:\?|&)farm_css_modules/;
export const stringifyQuery = (query) => {
if (!query.length) {
return '';
}
let queryStr = '';
for (const [key, value] of query) {
queryStr += `${key}${value ? `=${value}` : ''}&`;
}
return `${queryStr.slice(0, -1)}`;
};
export function formatId(id, query) {
// remove the adapter internal virtual module flag
if (isStartAdapterVirtualModule(id)) {
id = id?.replace(VITE_ADAPTER_VIRTUAL_MODULE, '');
}
if (!query.length) {
return id;
}
return `${id}?${stringifyQuery(query)}`;
}
// determine if it is the adapter's internal virtual module
export function isStartAdapterVirtualModule(id) {
return id?.startsWith(VITE_ADAPTER_VIRTUAL_MODULE);
}
export function isStartsWithSlash(str) {
return str?.startsWith('/');
}
export function addAdapterVirtualModuleFlag(id) {
return VITE_ADAPTER_VIRTUAL_MODULE + id;
}
export function normalizeAdapterVirtualModule(id) {
const path = removeQuery(id);
// If resolveIdResult is a path starting with / and the file at that path does not exist
// then it is considered an internal virtual module
if (isStartsWithSlash(path) && !fse.pathExistsSync(path))
return addAdapterVirtualModuleFlag(id);
return id;
}
// normalize path for windows the same as Vite
export function normalizePath(p) {
return path.posix.normalize(process.platform === 'win32' ? p.replace(/\\/g, '/') : p);
}
export const removeQuery = (path) => {
const queryIndex = path.indexOf('?');
if (queryIndex !== -1) {
return path.slice(0, queryIndex);
}
return revertNormalizePath(path.concat(''));
};
export function revertNormalizePath(p) {
return process.platform === 'win32' ? p.replace(/\//g, '\\') : p;
}
export function getCssModuleType(id) {
for (const [reg, lang] of CSS_LANGS_RES) {
if (reg.test(id)) {
return lang;
}
}
return null;
}
export function getJsModuleType(id) {
for (const [reg, lang] of JS_LANGS_RES) {
if (reg.test(id)) {
return lang;
}
}
return null;
}
export function formatLoadModuleType(id) {
const cssModuleType = getCssModuleType(id);
if (cssModuleType) {
return cssModuleType;
}
const jsModuleType = getJsModuleType(id);
if (jsModuleType) {
return jsModuleType;
}
return 'js';
}
export function formatTransformModuleType(id) {
return formatLoadModuleType(id);
}
// normalize invalid characters in id, for example: \0
// because characters like \0 have issues when passing to Farm's rust compiler
export function encodeStr(str) {
return str.replace(/\0/g, '\\0');
}
export function decodeStr(str) {
return str.replace(/\\0/g, '\0');
}
export function deleteUndefinedPropertyDeeply(obj) {
if (typeof obj !== 'object') {
return;
}
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
continue;
}
if (Array.isArray(obj[key])) {
obj[key] = obj[key].filter((item) => item !== undefined);
}
else if (obj[key] === undefined) {
delete obj[key];
}
else if (typeof obj[key] === 'object') {
deleteUndefinedPropertyDeeply(obj[key]);
}
}
}
export function throwIncompatibleError(pluginName, readingObject, allowedKeys, key) {
throw new Error(`Vite plugin '${pluginName}' is not compatible with Farm for now. Because it uses ${readingObject}['${String(key)}'] which is not supported by Farm. Current supported keys are: ${allowedKeys.join(',')}`);
}
export function transformResourceInfo2RollupRenderedChunk(info) {
const { modules, moduleIds, name, data } = info;
const { dynamicImports, importedBindings, imports, exports, isDynamicEntry, isEntry, isImplicitEntry } = data;
return {
dynamicImports,
fileName: name,
implicitlyLoadedBefore: [],
importedBindings,
imports,
modules: Object.entries(modules).reduce((result, [key, val]) => ({
...result,
[key]: {
code: val.renderedContent,
renderedLength: val.renderedLength,
originalLength: val.originalLength,
removedExports: [],
renderedExports: []
}
}), {}),
referencedFiles: [],
exports,
facadeModuleId: null,
isDynamicEntry,
isEntry,
isImplicitEntry,
moduleIds,
name,
type: 'chunk'
};
}
export function transformResourceInfo2RollupResource(resource) {
// Rollup/Vite only treat js files as chunk
if (resource.info && resource.resourceType === 'js') {
const source = Buffer.from(resource.bytes).toString('utf-8');
return {
...transformResourceInfo2RollupRenderedChunk(resource.info),
type: 'chunk',
code: source,
name: resource.name,
map: undefined,
sourcemapFileName: null,
preliminaryFileName: resource.origin.value
};
}
else {
return {
fileName: resource.name,
name: resource.name,
needsCodeReference: false,
source: Uint8Array.from(resource.bytes),
type: 'asset'
};
}
}
export function transformRollupResource2FarmResource(chunk, originResource) {
if (chunk.type === 'chunk') {
return {
...originResource,
bytes: Array.from(Buffer.from(chunk.code)),
emitted: originResource.emitted,
name: chunk.name
};
}
else {
return {
bytes: Array.from(chunk.source),
emitted: originResource.emitted,
name: chunk.name,
origin: originResource.origin,
resourceType: originResource.resourceType
};
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const notSupport = (method) => () => {
console.warn(`${method} not support`);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const noop = () => void 0;
function transformFarmFormatToRollupFormat(config) {
if (config.format === 'esm') {
return 'es';
}
else if (config.format === 'cjs') {
if (config.targetEnv === 'node')
return 'cjs';
return 'amd';
}
}
export function transformFarmConfigToRollupNormalizedOutputOptions(config) {
return {
amd: { autoId: false, define: 'define', forceJsExtensionForImports: false },
assetFileNames: config.output.assetsFilename,
chunkFileNames: config.output.filename,
compact: Boolean(config.minify),
dir: config.output.path,
dynamicImportInCjs: true,
entryFileNames: config.output.entryFilename,
esModule: 'if-default-prop',
experimentalMinChunkSize: config?.partialBundling?.targetMinSize || 1,
exports: 'auto',
extend: false,
externalImportAssertions: false,
// externalImportAttributes: true,
externalLiveBindings: true,
format: transformFarmFormatToRollupFormat(config.output),
freeze: false,
generatedCode: {
arrowFunctions: false,
constBindings: false,
objectShorthand: false,
reservedNamesAsProps: true,
symbols: false
},
globals: {},
hoistTransitiveImports: true,
indent: true,
inlineDynamicImports: false,
manualChunks: {},
minifyInternalExports: true,
noConflict: false,
paths: {},
plugins: [],
preserveModules: false,
sourcemap: Boolean(config.sourcemap),
sourcemapExcludeSources: false,
strict: true,
systemNullSetters: true,
validate: false,
banner: notSupport('banner'),
footer: notSupport('footer'),
interop: notSupport('interop'),
outro: notSupport('outro'),
intro: notSupport('intro'),
sanitizeFileName: notSupport('sanitizeFileName'),
sourcemapIgnoreList: notSupport('sourcemapIgnoreList'),
dynamicImportFunction: undefined,
experimentalDeepDynamicChunkOptimization: false,
file: undefined,
name: undefined,
namespaceToStringTag: false,
preferConst: false,
preserveModulesRoot: undefined,
sourcemapBaseUrl: undefined,
sourcemapFile: undefined,
sourcemapFileNames: undefined,
sourcemapPathTransform: undefined
};
}
export function transformFarmConfigToRollupNormalizedInputOptions(config) {
return {
context: 'undefined',
experimentalCacheExpiry: 10,
experimentalLogSideEffects: false,
input: config.input,
logLevel: 'info',
makeAbsoluteExternalsRelative: 'ifRelativeSource',
maxParallelFileOps: 20,
perf: false,
plugins: [],
preserveEntrySignatures: 'exports-only',
preserveSymlinks: false,
shimMissingExports: false,
strictDeprecations: false,
treeshake: config.treeShaking && {
moduleSideEffects: () => false,
annotations: true,
correctVarValueBeforeDeclaration: false,
manualPureFunctions: [],
propertyReadSideEffects: true,
tryCatchDeoptimization: true,
unknownGlobalSideEffects: true
},
acorn: undefined,
acornInjectPlugins: undefined,
cache: undefined,
external: undefined,
inlineDynamicImports: undefined,
manualChunks: undefined,
maxParallelFileReads: undefined,
moduleContext: undefined,
onLog: noop,
onwarn: noop,
preserveModules: undefined
};
}
export function normalizeFilterPath(path) {
if (process.platform === 'win32') {
return compatibleWin32Path(path);
}
return path;
}
function compatibleWin32Path(path) {
return path.replaceAll('/', '\\\\');
}
//# sourceMappingURL=utils.js.map