packages/ice/src/requireHook.ts (79 lines of code) (raw):
// inspired by https://github.com/vercel/next.js/blob/canary/packages/next/build/webpack/require-hook.ts
// sync injects a hook for webpack and webpack/... requires to use the internal ncc webpack version
// this is in order for userland plugins to attach to the same webpack instance as next.js
// the individual compiled modules are as defined for the compilation in bundles/webpack/packages/*
import * as path from 'path';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
export function getFileName(filePath: string) {
return filePath.split('/').slice(-1)[0];
}
const webpackPlugins = [
// plugins require the same webpack instance
'webpack/lib/LibraryTemplatePlugin',
'webpack/lib/node/NodeTargetPlugin',
'webpack/lib/node/NodeTemplatePlugin',
'webpack/lib/NormalModule',
'webpack/lib/optimize/LimitChunkCountPlugin',
'webpack/lib/SingleEntryPlugin',
'webpack/lib/webworker/WebWorkerTemplatePlugin',
'webpack/lib/node/NodeEnvironmentPlugin',
'webpack/lib/ModuleFilenameHelpers',
'webpack/lib/GraphHelpers',
'webpack/lib/ExternalsPlugin',
'webpack/lib/web/FetchCompileAsyncWasmPlugin',
'webpack/lib/web/FetchCompileWasmPlugin',
'webpack/lib/runtime/StartupChunkDependenciesPlugin',
'webpack/lib/javascript/JavascriptModulesPlugin',
'webpack/lib/javascript/StartupHelpers',
'webpack/lib/util/identifier',
'webpack/lib/util/compileBooleanMatcher',
'webpack/lib/ModuleNotFoundError',
'webpack/lib/util/LazySet',
'webpack/lib/util/fs',
'webpack/lib/util/makeSerializable',
'webpack/lib/util/SortableSet',
'webpack/lib/dependencies/StaticExportsDependency',
'webpack/lib/dependencies/EntryDependency',
'webpack/lib/ModuleFactory',
'webpack/lib/dependencies/ModuleDependency',
'webpack/lib/util/create-schema-validation',
'webpack/lib/util/extractUrlAndGlobal',
'webpack/lib/Compilation',
'webpack/lib/util/semver',
'webpack/lib/WebpackError',
'webpack/lib/util/comparators',
'webpack/lib/runtime/StartupEntrypointRuntimeModule',
'webpack/lib/util/SetHelpers',
'webpack/lib/javascript/ChunkHelpers',
'webpack/lib/HotUpdateChunk',
];
export function getHookFiles() {
const webpackDir = path.join(require.resolve('@ice/bundles/compiled/webpack'), '../');
const createPluginMapping = (pluginPath: string, withJsExtension = false) => [
withJsExtension ? `${pluginPath}.js` : pluginPath,
pluginPath.replace(/^webpack\/lib\/((web|node|optimize|webworker|runtime|javascript|util|dependencies)\/)?/, webpackDir),
];
const pluginMap = webpackPlugins.map(pluginPath => createPluginMapping(pluginPath));
const pluginMapWithJs = webpackPlugins.map(pluginPath => createPluginMapping(pluginPath, true));
return [
['webpack', `${webpackDir}webpack-lib`],
['webpack/lib/webpack', `${webpackDir}webpack-lib`],
['webpack/lib/webpack.js', `${webpackDir}webpack-lib`],
['webpack/hot/dev-server', `${webpackDir}hot/dev-server`],
['webpack/hot/only-dev-server', `${webpackDir}hot/only-dev-server`],
['webpack/hot/emitter', `${webpackDir}hot/emitter`],
...pluginMap,
...pluginMapWithJs,
];
}
function hijackWebpack() {
const hookPropertyMap = new Map(
getHookFiles().map(([request, replacement]) => [request, require.resolve(replacement)]),
);
// eslint-disable-next-line global-require
const mod = require('module');
const resolveFilename = mod._resolveFilename;
mod._resolveFilename = function (request: string, parent: any, isMain: boolean, options: any) {
const hookResolved = hookPropertyMap.get(request);
if (hookResolved) {
request = hookResolved;
}
return resolveFilename.call(mod, request, parent, isMain, options);
};
}
// avoid multi webpack
hijackWebpack();