@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.
169 lines • 5.87 kB
JavaScript
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { Compiler as BindingCompiler } from '../../binding/index.js';
import { Logger } from '../utils/logger.js';
export const VIRTUAL_FARM_DYNAMIC_IMPORT_SUFFIX = '.farm_dynamic_import_virtual_module';
export class Compiler {
constructor(config, logger = new Logger()) {
this.config = config;
this.logger = logger;
this._updateQueue = [];
this._onUpdateFinishQueue = [];
this.compiling = false;
this._bindingCompiler = new BindingCompiler(this.config);
}
async traceDependencies() {
return this._bindingCompiler.traceDependencies();
}
async traceModuleGraph() {
return this._bindingCompiler.traceModuleGraph();
}
async compile() {
if (this.compiling) {
this.logger.error('Already compiling', {
exit: true
});
}
this.compiling = true;
if (process.env.FARM_PROFILE) {
this._bindingCompiler.compileSync();
}
else {
await this._bindingCompiler.compile();
}
this.compiling = false;
}
compileSync() {
if (this.compiling) {
this.logger.error('Already compiling', {
exit: true
});
}
this.compiling = true;
this._bindingCompiler.compileSync();
this.compiling = false;
}
async update(paths, sync = false, ignoreCompilingCheck = false, generateUpdateResource = true) {
let resolve;
const promise = new Promise((r) => {
resolve = r;
});
// if there is already a update process, we need to wait for it to finish
if (this.compiling && !ignoreCompilingCheck) {
this._updateQueue.push({ paths, resolve });
return promise;
}
this.compiling = true;
try {
const res = await this._bindingCompiler.update(paths, async () => {
const next = this._updateQueue.shift();
if (next) {
await this.update(next.paths, true, true, generateUpdateResource).then(next.resolve);
}
else {
this.compiling = false;
while (this._onUpdateFinishQueue.length) {
if (this.compiling) {
break;
}
const cb = this._onUpdateFinishQueue.shift();
await cb();
}
}
}, sync, generateUpdateResource);
return res;
}
catch (e) {
this.compiling = false;
throw e;
}
}
hasModule(resolvedPath) {
return this._bindingCompiler.hasModule(resolvedPath);
}
getParentFiles(idOrResolvedPath) {
return this._bindingCompiler.getParentFiles(idOrResolvedPath);
}
resources() {
return this._bindingCompiler.resources();
}
resource(path) {
return this._bindingCompiler.resource(path);
}
resourcesMap() {
return this._bindingCompiler.resourcesMap();
}
writeResourcesToDisk() {
const resources = this.resources();
const configOutputPath = this.config.config.output.path;
const outputPath = path.isAbsolute(configOutputPath)
? configOutputPath
: path.join(this.config.config.root, configOutputPath);
for (const [name, resource] of Object.entries(resources)) {
// remove query params and hash of name
const nameWithoutQuery = name.split('?')[0];
const nameWithoutHash = nameWithoutQuery.split('#')[0];
let filePath = path.join(outputPath, nameWithoutHash);
if (!existsSync(path.dirname(filePath))) {
mkdirSync(path.dirname(filePath), { recursive: true });
}
writeFileSync(filePath, resource);
}
this.callWriteResourcesHook();
}
callWriteResourcesHook() {
for (const jsPlugin of this.config.jsPlugins ?? []) {
jsPlugin.writeResources?.executor?.({
resourcesMap: this._bindingCompiler.resourcesMap(),
config: this.config.config
});
}
}
removeOutputPathDir() {
const outputPath = this.outputPath();
if (existsSync(outputPath)) {
rmSync(outputPath, { recursive: true });
}
}
resolvedWatchPaths() {
return this._bindingCompiler.watchModules();
}
resolvedModulePaths(root) {
return this._bindingCompiler
.relativeModulePaths()
.map((p) => this.transformModulePath(root, p));
}
transformModulePath(root, p) {
if (p.endsWith(VIRTUAL_FARM_DYNAMIC_IMPORT_SUFFIX)) {
p = p.slice(0, -VIRTUAL_FARM_DYNAMIC_IMPORT_SUFFIX.length);
}
if (path.isAbsolute(p)) {
return p;
}
if (p.includes('?')) {
return path.join(root, p.split('?')[0]);
}
return path.join(root, p);
}
onUpdateFinish(cb) {
this._onUpdateFinishQueue.push(cb);
}
outputPath() {
const { output, root } = this.config.config;
const configOutputPath = output.path;
const outputPath = path.isAbsolute(configOutputPath)
? configOutputPath
: path.join(root, configOutputPath);
return outputPath;
}
addExtraWatchFile(root, paths) {
this._bindingCompiler.addWatchFiles(root, paths);
}
stats() {
return this._bindingCompiler.stats();
}
invalidateModule(moduleId) {
this._bindingCompiler.invalidateModule(moduleId);
}
}
//# sourceMappingURL=index.js.map