feat(util/lazyRequire): tool for loading CommonJS modules lazily

This commit is contained in:
Ivan Kopeykin 2019-12-02 18:37:55 +03:00
parent aea30c3a1e
commit 4598ea539b
5 changed files with 96 additions and 81 deletions

View File

@ -13,11 +13,21 @@ const { compareModulesByIdentifier } = require("../util/comparators");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
let generatorSchema;
let parserSchema;
let AssetGenerator;
let AssetParser;
let AssetSourceGenerator;
const lazyRequire = require("../util/lazyRequire")(require);
const generatorSchema = lazyRequire(
"../../schemas/plugins/AssetModulesPluginGenerator.json",
false
);
const parserSchema = lazyRequire(
"../../schemas/plugins/AssetModulesPluginParser.json",
false
);
/** @type {typeof import('./AssetGenerator')} */
const AssetGenerator = lazyRequire("./AssetGenerator");
/** @type {typeof import('./AssetParser')} */
const AssetParser = lazyRequire("./AssetParser");
/** @type {typeof import('./AssetSourceGenerator')} */
const AssetSourceGenerator = lazyRequire("./AssetSourceGenerator");
const type = "asset";
const plugin = "AssetModulesPlugin";
@ -34,9 +44,6 @@ class AssetModulesPlugin {
normalModuleFactory.hooks.createParser
.for("asset")
.tap(plugin, parserOptions => {
if (parserSchema === undefined) {
parserSchema = require("../../schemas/plugins/AssetModulesPluginParser.json");
}
validateOptions(parserSchema, parserOptions, {
name: "Asset Modules Plugin",
baseDataPath: "parser"
@ -50,44 +57,23 @@ class AssetModulesPlugin {
};
}
if (AssetParser === undefined) {
AssetParser = require("./AssetParser");
}
return new AssetParser(dataUrlCondition);
});
normalModuleFactory.hooks.createParser
.for("asset/inline")
.tap(plugin, parserOptions => {
if (AssetParser === undefined) {
AssetParser = require("./AssetParser");
}
return new AssetParser(true);
});
.tap(plugin, parserOptions => new AssetParser(true));
normalModuleFactory.hooks.createParser
.for("asset/resource")
.tap(plugin, parserOptions => {
if (AssetParser === undefined) {
AssetParser = require("./AssetParser");
}
return new AssetParser(false);
});
.tap(plugin, parserOptions => new AssetParser(false));
normalModuleFactory.hooks.createParser
.for("asset/source")
.tap(plugin, parserOptions => {
if (AssetParser === undefined) {
AssetParser = require("./AssetParser");
}
return new AssetParser(false);
});
.tap(plugin, parserOptions => new AssetParser(false));
for (const type of ["asset", "asset/inline"]) {
normalModuleFactory.hooks.createGenerator
.for(type)
// eslint-disable-next-line no-loop-func
.tap(plugin, generatorOptions => {
if (generatorSchema === undefined) {
generatorSchema = require("../../schemas/plugins/AssetModulesPluginGenerator.json");
}
validateOptions(generatorSchema, generatorOptions, {
name: "Asset Modules Plugin",
baseDataPath: "generator"
@ -102,28 +88,15 @@ class AssetModulesPlugin {
};
}
if (AssetGenerator === undefined) {
AssetGenerator = require("./AssetGenerator");
}
return new AssetGenerator(compilation, dataUrl);
});
}
normalModuleFactory.hooks.createGenerator
.for("asset/resource")
.tap(plugin, () => {
if (AssetGenerator === undefined) {
AssetGenerator = require("./AssetGenerator");
}
return new AssetGenerator(compilation);
});
.tap(plugin, () => new AssetGenerator(compilation));
normalModuleFactory.hooks.createGenerator
.for("asset/source")
.tap(plugin, () => {
if (AssetSourceGenerator === undefined) {
AssetSourceGenerator = require("./AssetSourceGenerator");
}
return new AssetSourceGenerator();
});
.tap(plugin, () => new AssetSourceGenerator());
compilation.hooks.renderManifest.tap(plugin, (result, options) => {
const { chunkGraph } = compilation;

View File

@ -11,7 +11,11 @@ const JsonParser = require("./JsonParser");
/** @typedef {import("../Compiler")} Compiler */
let parserSchema;
const lazyRequire = require("../util/lazyRequire")(require);
const parserSchema = lazyRequire(
"../../schemas/plugins/JsonModulesPluginParser.json",
false
);
class JsonModulesPlugin {
/**
@ -26,9 +30,6 @@ class JsonModulesPlugin {
normalModuleFactory.hooks.createParser
.for("json")
.tap("JsonModulesPlugin", parserOptions => {
if (parserSchema === undefined) {
parserSchema = require("../../schemas/plugins/JsonModulesPluginParser.json");
}
validateOptions(parserSchema, parserOptions, {
name: "Json Modules Plugin",
baseDataPath: "parser"

47
lib/util/lazyRequire.js Normal file
View File

@ -0,0 +1,47 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @vankop
*/
"use strict";
/* Fork from https://github.com/sindresorhus/import-lazy */
const lazy = (importedModule, requireFn, moduleId) =>
importedModule === undefined ? requireFn(moduleId) : importedModule;
/**
* @template T
* @callback LazyRequire
* @param {string} moduleId path to module
* @param {boolean} [isFunction] flag for Proxy type,
* if true returns function, object otherwise.
* True by default since webpack modules are mostly functions or classes
* @returns {T} module export
*/
/**
* @template T
* @param {Function} requireFn require function relative to parent module
* @returns {LazyRequire<T>} require function
*/
module.exports = requireFn => (moduleId, isFunction = true) => {
let importedModule;
const handler = {
get: (target, property) => {
importedModule = lazy(importedModule, requireFn, moduleId);
return Reflect.get(importedModule, property);
},
apply: (target, thisArgument, argumentsList) => {
importedModule = lazy(importedModule, requireFn, moduleId);
return Reflect.apply(importedModule, thisArgument, argumentsList);
},
construct: (target, argumentsList) => {
importedModule = lazy(importedModule, requireFn, moduleId);
return Reflect.construct(importedModule, argumentsList);
}
};
return new Proxy(isFunction ? function() {} : {}, handler);
};

View File

@ -20,9 +20,15 @@ const { compareModulesByIdentifier } = require("../util/comparators");
/** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry */
/** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions */
let AsyncWebAssemblyGenerator;
let AsyncWebAssemblyJavascriptGenerator;
let AsyncWebAssemblyParser;
const lazyRequire = require("../util/lazyRequire")(require);
/** @type {typeof import('./AsyncWebAssemblyGenerator')} */
const AsyncWebAssemblyGenerator = lazyRequire("./AsyncWebAssemblyGenerator");
/** @type {typeof import('./AsyncWebAssemblyJavascriptGenerator')} */
const AsyncWebAssemblyJavascriptGenerator = lazyRequire(
"./AsyncWebAssemblyJavascriptGenerator"
);
/** @type {typeof import('./AsyncWebAssemblyParser')} */
const AsyncWebAssemblyParser = lazyRequire("./AsyncWebAssemblyParser");
/**
* @typedef {Object} RenderContext
@ -89,21 +95,13 @@ class AsyncWebAssemblyModulesPlugin {
normalModuleFactory.hooks.createParser
.for("webassembly/async")
.tap("AsyncWebAssemblyModulesPlugin", () => {
if (AsyncWebAssemblyParser === undefined) {
AsyncWebAssemblyParser = require("./AsyncWebAssemblyParser");
}
return new AsyncWebAssemblyParser();
});
.tap(
"AsyncWebAssemblyModulesPlugin",
() => new AsyncWebAssemblyParser()
);
normalModuleFactory.hooks.createGenerator
.for("webassembly/async")
.tap("AsyncWebAssemblyModulesPlugin", () => {
if (AsyncWebAssemblyGenerator === undefined) {
AsyncWebAssemblyGenerator = require("./AsyncWebAssemblyGenerator");
}
if (AsyncWebAssemblyJavascriptGenerator === undefined) {
AsyncWebAssemblyJavascriptGenerator = require("./AsyncWebAssemblyJavascriptGenerator");
}
return Generator.byType({
javascript: new AsyncWebAssemblyJavascriptGenerator(
compilation.outputOptions.webassemblyModuleFilename

View File

@ -17,9 +17,16 @@ const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError
/** @typedef {import("../ModuleTemplate")} ModuleTemplate */
/** @typedef {import("../ModuleTemplate").RenderContext} RenderContext */
let WebAssemblyGenerator;
let WebAssemblyJavascriptGenerator;
let WebAssemblyParser;
const lazyRequire = require("../util/lazyRequire")(require);
/** @type {typeof import('./WebAssemblyGenerator')} */
const WebAssemblyGenerator = lazyRequire("./WebAssemblyGenerator");
/** @type {typeof import('./WebAssemblyJavascriptGenerator')} */
const WebAssemblyJavascriptGenerator = lazyRequire(
"./WebAssemblyJavascriptGenerator"
);
/** @type {typeof import('./WebAssemblyParser')} */
const WebAssemblyParser = lazyRequire("./WebAssemblyParser");
class WebAssemblyModulesPlugin {
constructor(options) {
@ -46,22 +53,11 @@ class WebAssemblyModulesPlugin {
normalModuleFactory.hooks.createParser
.for("webassembly/sync")
.tap("WebAssemblyModulesPlugin", () => {
if (WebAssemblyParser === undefined) {
WebAssemblyParser = require("./WebAssemblyParser");
}
return new WebAssemblyParser();
});
.tap("WebAssemblyModulesPlugin", () => new WebAssemblyParser());
normalModuleFactory.hooks.createGenerator
.for("webassembly/sync")
.tap("WebAssemblyModulesPlugin", () => {
if (WebAssemblyGenerator === undefined) {
WebAssemblyGenerator = require("./WebAssemblyGenerator");
}
if (WebAssemblyJavascriptGenerator === undefined) {
WebAssemblyJavascriptGenerator = require("./WebAssemblyJavascriptGenerator");
}
return Generator.byType({
javascript: new WebAssemblyJavascriptGenerator(),
webassembly: new WebAssemblyGenerator(this.options)