Skip to content

Commit

Permalink
Replace import(...) with Promise.resolve(...)
Browse files Browse the repository at this point in the history
  • Loading branch information
koistya committed Feb 18, 2021
1 parent 8d0034a commit 3d371eb
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 65 deletions.
1 change: 0 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@
.yarn
.yarnrc.yml
.pnp.js
tsconfig.json
yarn.lock
5 changes: 1 addition & 4 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
{
"recommendations": [
"arcanis.vscode-zipfs",
"esbenp.prettier-vscode"
]
"recommendations": ["arcanis.vscode-zipfs", "esbenp.prettier-vscode"]
}
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
".gitignore": true,
".npmignore": true,
".pnp.js": true,
".yarn": true,
".yarnrc.yml": true,
"yarn.lock": true
},
"search.exclude": {
"**/.yarn": true,
"**/.pnp.*": true
Expand Down
75 changes: 75 additions & 0 deletions IgnoreAsyncImportsPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* @copyright 2021-present Kriasoft (https://git.io/JtoKE)
*
* @typedef {import("webpack").Compiler} Compiler
* @typedef {import("webpack").javascript.JavascriptParser} JavascriptParser
*/

const path = require("path");
const webpack = require("webpack");
const ImportDependency = require("./ImportDependency");

/**
* Excludes dynamically imported dependencies from the output bundle.
*/
class IgnoreAsyncImportsPlugin {
/**
* Creates a new instance of the plugin.
*
* @param {Object} config Ignore options.
*/
constructor(config = {}) {
this.config = config;
}

/**
* @param {Compiler} compiler
*/
apply(compiler) {
this.name = this.constructor.name;
const handleParser = this.handleParser.bind(this);

compiler.hooks.compilation.tap(
this.name,
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
ImportDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
ImportDependency,
new ImportDependency.Template()
);

normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap(this.name, handleParser);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap(this.name, handleParser);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap(this.name, handleParser);
}
);
}

/**
* @param {JavascriptParser} parser
*/
handleParser(parser, parserOptions) {
if (parserOptions.import !== undefined && !parserOptions.import) {
return;
}

// Replace import(...) calls with Promise.resolve(...)
parser.hooks.importCall.tap(this.name, (expr) => {
const dep = new ImportDependency(expr.source.value, expr.range);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return true;
});
}
}

module.exports = IgnoreAsyncImportsPlugin;
73 changes: 73 additions & 0 deletions ImportDependency.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Florent Cailhol @ooflorent
*/

"use strict";

const InitFragment = require("webpack/lib/InitFragment");
const ModuleDependency = require("webpack/lib/dependencies/ModuleDependency");

/** @typedef {import("webpack").sources.ReplaceSource} ReplaceSource */
/** @typedef {import("webpack").ChunkGraph} ChunkGraph */
/** @typedef {import("webpack").Dependency} Dependency */
/** @typedef {import("webpack").Dependency.UpdateHashContext} UpdateHashContext */
/** @typedef {import("webpack").util.Hash} Hash */

class ImportDependency extends ModuleDependency {
constructor(request, range) {
super(request);
this.range = range;
}

get type() {
return "async import";
}

get category() {
return "esm";
}

/**
* Update the hash
* @param {Hash} hash hash to be updated
* @param {UpdateHashContext} context context
* @returns {void}
*/
updateHash(hash, context) {
hash.update(this.request);
}

serialize(context) {
const { write } = context;
write(this.request);
write(this.userRequest);
write(this.range);
super.serialize(context);
}

deserialize(context) {
const { read } = context;
this.request = read();
this.userRequest = read();
this.range = read();
super.deserialize(context);
}
}

class ImportDependencyTemplate extends ModuleDependency.Template {
/**
* @param {Dependency} dependency the dependency for which the template should be applied
* @param {ReplaceSource} source the current replace source which can be modified
* @returns {void}
*/
apply(dependency, source) {
const dep = /** @type {ImportDependency} */ (dependency);
// TODO: Provide the requested chunk name
source.replace(dep.range[0], dep.range[1] - 1, "Promise.resolve({})");
}
}

ImportDependency.Template = ImportDependencyTemplate;

module.exports = ImportDependency;
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ module.exports = [
];
```

All the `import(...)` expressions within the "proxy" bundle in the example above
will be replaced with `Promise.resolve(...)`.

## Related Projects

- [Node.js API Starter](https://github.com/kriasoft/nodejs-api-starter) - Monorepo project template based on Yarn v2, GraphQL.js, React, and Relay.
Expand Down
61 changes: 4 additions & 57 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,9 @@
/**
* @copyright 2021-present Kriasoft (https://git.io/JtoKE)
*
* @typedef {import("webpack").Compiler} Compiler
* @typedef {import("webpack").javascript.JavascriptParser} JavascriptParser
*/

const path = require("path");
const webpack = require("webpack");
const IgnoreAsyncImportsPlugin = require("./IgnoreAsyncImportsPlugin");

/**
* Excludes dynamically imported dependencies from the output bundle.
*/
class IgnoreAsyncImportsPlugin {
/**
* Creates a new instance of the plugin.
*
* @param {Object} config Ignore options.
*/
constructor(config = {}) {
this.config = config;
}

/**
* @param {Compiler} compiler
*/
apply(compiler) {
this.name = this.constructor.name;
const handleParser = this.handleParser.bind(this);

compiler.hooks.compilation.tap(
this.name,
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap(this.name, handleParser);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap(this.name, handleParser);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap(this.name, handleParser);
}
);
}

/**
* @param {JavascriptParser} parser
*/
handleParser(parser, parserOptions) {
if (parserOptions.import !== undefined && !parserOptions.import) {
return;
}

// Exclude dynamically imported dependencies.
parser.hooks.importCall.tap(this.name, () => {
return false;
});
}
}

module.exports = { IgnoreAsyncImportsPlugin };
module.exports = {
IgnoreAsyncImportsPlugin,
};
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
{
"name": "ignore-webpack-plugin",
"version": "0.1.1",
"version": "0.2.0",
"description": "Excludes dynamically imported dependencies from the output bundle.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc index.js --declaration --allowJs --emitDeclarationOnly --outFile types.d.ts"
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": "kriasoft/ignore-webpack-plugin",
"keywords": [
Expand Down

0 comments on commit 3d371eb

Please sign in to comment.