Skip to content

Commit

Permalink
perf(dts-plugin): only block build process in prod env when generatin…
Browse files Browse the repository at this point in the history
…g types
  • Loading branch information
2heal1 committed Jan 21, 2025
1 parent 3d83f9d commit b1f0153
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 67 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-pianos-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@module-federation/dts-plugin': patch
---

perf(dts-plugin): only block build process in prod env when generating types
204 changes: 137 additions & 67 deletions packages/dts-plugin/src/plugins/GenerateTypesPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Compiler, WebpackPluginInstance } from 'webpack';
import type { Compilation, Compiler, WebpackPluginInstance } from 'webpack';
import fs from 'fs';
import path from 'path';
import { isDev, getCompilerOutputDir } from './utils';
Expand Down Expand Up @@ -88,7 +88,139 @@ export class GenerateTypesPlugin implements WebpackPluginInstance {
return fn;
};
const generateTypesFn = getGenerateTypesFn();
let compiledOnce = false;

const emitTypesFiles = async (compilation: Compilation) => {
// Dev types will be generated by DevPlugin, the archive filename usually is dist/.dev-server.zip
try {
await consumeTypesPromise;

const { zipTypesPath, apiTypesPath, zipName, apiFileName } =
retrieveTypesAssetsInfo(finalOptions.remote);

if (isProd && zipName && compilation.getAsset(zipName)) {
return;
}

await generateTypesFn(finalOptions);
const config = finalOptions.remote.moduleFederationConfig;
let zipPrefix = '';
if (typeof config.manifest === 'object' && config.manifest.filePath) {
zipPrefix = config.manifest.filePath;
} else if (
typeof config.manifest === 'object' &&
config.manifest.fileName
) {
zipPrefix = path.dirname(config.manifest.fileName);
} else if (config.filename) {
zipPrefix = path.dirname(config.filename);
}

if (isProd) {
const zipAssetName = path.join(zipPrefix, zipName);
const apiAssetName = path.join(zipPrefix, apiFileName);
if (zipTypesPath && !compilation.getAsset(zipAssetName)) {
compilation.emitAsset(
path.join(zipPrefix, zipName),
new compiler.webpack.sources.RawSource(
fs.readFileSync(zipTypesPath),
false,
),
);
}

if (apiTypesPath && !compilation.getAsset(apiAssetName)) {
compilation.emitAsset(
path.join(zipPrefix, apiFileName),
new compiler.webpack.sources.RawSource(
fs.readFileSync(apiTypesPath),
false,
),
);
}
callback();
} else {
const isEEXIST = (err: NodeJS.ErrnoException) => {
return err.code == 'EEXIST';
};
if (zipTypesPath) {
const zipContent = fs.readFileSync(zipTypesPath);
const zipOutputPath = path.join(
compiler.outputPath,
zipPrefix,
zipName,
);
await new Promise<void>((resolve, reject) => {
compiler.outputFileSystem.mkdir(
path.dirname(zipOutputPath),
(err) => {
if (err) {
if (!isEEXIST(err)) {
reject(err);
}
} else {
compiler.outputFileSystem.writeFile(
zipOutputPath,
zipContent,
(writeErr) => {
if (writeErr) {
if (!isEEXIST(writeErr)) {
reject(writeErr);
}
} else {
resolve();
}
},
);
}
},
);
});
}

if (apiTypesPath) {
const apiContent = fs.readFileSync(apiTypesPath);
const apiOutputPath = path.join(
compiler.outputPath,
zipPrefix,
apiFileName,
);
await new Promise<void>((resolve, reject) => {
compiler.outputFileSystem.mkdir(
path.dirname(apiOutputPath),
(err) => {
if (err) {
if (!isEEXIST(err)) {
reject(err);
}
} else {
compiler.outputFileSystem.writeFile(
apiOutputPath,
apiContent,
(writeErr) => {
if (writeErr) {
if (!isEEXIST(writeErr)) {
reject(writeErr);
}
} else {
resolve();
}
},
);
}
},
);
});
}

callback();
}
} catch (err) {
callback();
if (finalOptions.displayErrorInTerminal) {
console.error('Error in mf:generateTypes processAssets hook:', err);
}
}
};

compiler.hooks.thisCompilation.tap('mf:generateTypes', (compilation) => {
compilation.hooks.processAssets.tapPromise(
Expand All @@ -99,71 +231,9 @@ export class GenerateTypesPlugin implements WebpackPluginInstance {
compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER,
},
async () => {
await consumeTypesPromise;
try {
if (pluginOptions.dev === false && compiledOnce) {
return;
}

if (compiledOnce) {
// Dev types will be generated by DevPlugin, the archive filename usually is dist/.dev-server.zip
return;
}

const { zipTypesPath, apiTypesPath, zipName, apiFileName } =
retrieveTypesAssetsInfo(finalOptions.remote);
if (zipName && compilation.getAsset(zipName)) {
return;
}

await generateTypesFn(finalOptions);
const config = finalOptions.remote.moduleFederationConfig;
let zipPrefix = '';
if (
typeof config.manifest === 'object' &&
config.manifest.filePath
) {
zipPrefix = config.manifest.filePath;
} else if (
typeof config.manifest === 'object' &&
config.manifest.fileName
) {
zipPrefix = path.dirname(config.manifest.fileName);
} else if (config.filename) {
zipPrefix = path.dirname(config.filename);
}

const zipAssetName = path.join(zipPrefix, zipName);
if (zipTypesPath && !compilation.getAsset(zipAssetName)) {
compilation.emitAsset(
path.join(zipPrefix, zipName),
new compiler.webpack.sources.RawSource(
fs.readFileSync(zipTypesPath),
false,
),
);
}

const apiAssetName = path.join(zipPrefix, apiFileName);
if (apiTypesPath && !compilation.getAsset(apiAssetName)) {
compilation.emitAsset(
path.join(zipPrefix, apiFileName),
new compiler.webpack.sources.RawSource(
fs.readFileSync(apiTypesPath),
false,
),
);
}
compiledOnce = true;
callback();
} catch (err) {
callback();
if (finalOptions.displayErrorInTerminal) {
console.error(
'Error in mf:generateTypes processAssets hook:',
err,
);
}
const emitTypesFilesPromise = emitTypesFiles(compilation);
if (isProd) {
await emitTypesFilesPromise;
}
},
);
Expand Down

0 comments on commit b1f0153

Please sign in to comment.