Skip to content

Commit

Permalink
Feature: Full webpack5 support. (#157)
Browse files Browse the repository at this point in the history
* Add webpack5 support. Fixes #156 
* Add webpack5 test fixtures. Fixes #140 
* Test: Refactor test fixture base `webpack.config.js`.
* Test: Change handling of tree-shaking supported fixtures to compare production on v4+ and dev vs prod on v3-.
* Test: Remove `expose-loader` from `loaders` test scenario as just wasn't working on windows + v5.
* Test: Refactor and rename various internal test utilities.
  • Loading branch information
ryan-roemer authored Jan 19, 2021
1 parent 4b8809a commit b75d9f2
Show file tree
Hide file tree
Showing 16 changed files with 386 additions and 170 deletions.
7 changes: 7 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
History
=======

## UNRELEASED

* Feature: Add webpack5 support.
[#156](https://github.com/FormidableLabs/inspectpack/issues/156)
* Test: Change handling of tree-shaking supported fixtures to compare production on v4+ and dev vs prod on v3-.
* Test: Remove `expose-loader` from `loaders` test scenario as just wasn't working on windows + v5.

## 4.5.2

* Internal: Optimize `shouldBail` to used cached `getData()`.
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,14 +314,19 @@ module.exports = {
// ...
plugins: [
new StatsWriterPlugin({
fields: ["assets", "modules"]
fields: ["assets", "modules"],
stats: {
source: true // Needed for webpack5+
}
})
]
};
```

This uses the [`webpack-stats-plugin`](https://github.com/FormidableLabs/webpack-stats-plugin) to output at least the `assets` and `modules` fields of the stats object to a file named `stats.json` in the directory specified in `output.path`. There are lots of various [options](https://github.com/FormidableLabs/webpack-stats-plugin#statswriterpluginopts) for the `webpack-stats-plugin` that may suit your particular webpack config better than this example.

> ℹ️ **Webpack 5+ Note**: If you are using webpack5+ you will need to enable the `{ source: true }` options for the `stats` field for the plugin to include sources in stats output. In webpack versions previous to 5, this was enabled by default. The field is needed for internal determination as to whether or not a module is a real source file or a "synthetic" webpack added entry.

#### _Note_: Multiple entry points

If you configure `entry` with multiple entry points like:
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"build-test-wp": "node test/fixtures/packages/webpack.js --config ../../test/fixtures/config/webpack.config.js && node test/fixtures/packages/check-bundle.js",
"build-test-scenarios": "builder envs --envs-path=test/fixtures/config/scenarios.json build-test-wp --buffer --queue=1",
"build-test-modes": "builder envs build-test-scenarios \"[{\\\"WEBPACK_MODE\\\":\\\"development\\\"},{\\\"WEBPACK_MODE\\\":\\\"production\\\"}]\" --queue=2",
"build-test-versions": "builder envs build-test-modes \"[{\\\"WEBPACK_VERSION\\\":\\\"1\\\"},{\\\"WEBPACK_VERSION\\\":\\\"2\\\"},{\\\"WEBPACK_VERSION\\\":\\\"3\\\"},{\\\"WEBPACK_VERSION\\\":\\\"4\\\"}]\" --queue=4",
"build-test-versions": "builder envs --envs-path=test/fixtures/config/versions.json build-test-modes --queue=4",
"build-test": "builder run build-test-versions",
"build": "yarn run clean-lib && yarn run build-lib",
"watch": "tsc -w",
Expand Down Expand Up @@ -83,7 +83,6 @@
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-promise": "^4.2.1",
"execa": "^5.0.0",
"expose-loader": "^0.7.5",
"inspectpack-test-fixtures": "file:test/fixtures",
"mocha": "^8.2.1",
"mock-fs": "^4.12.0",
Expand Down
12 changes: 11 additions & 1 deletion src/lib/actions/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import {
IWebpackStatsModuleModules,
IWebpackStatsModules,
IWebpackStatsModuleSource,
IWebpackStatsModuleOrphan,
IWebpackStatsModuleSynthetic,
RWebpackStats,
RWebpackStatsModuleModules,
RWebpackStatsModuleSource,
RWebpackStatsModuleOrphan,
RWebpackStatsModuleSynthetic,
} from "../interfaces/webpack-stats";
import { toPosixPath } from "../util/files";
Expand Down Expand Up @@ -217,7 +219,15 @@ export abstract class Action {
return list.concat(this.getSourceMods(modsMod.modules, chunks));

} else if (isRight(RWebpackStatsModuleSource.decode(mod))) {
// Easy case -- a normal source code module.
// webpack5+: Check if an orphan and just skip entirely.
if (
isRight(RWebpackStatsModuleOrphan.decode(mod)) &&
(mod as IWebpackStatsModuleOrphan).orphan
) {
return list;
}

// Base case -- a normal source code module that is **not** an orphan.
const srcMod = mod as IWebpackStatsModuleSource;
identifier = srcMod.identifier;
name = srcMod.name;
Expand Down
21 changes: 18 additions & 3 deletions src/lib/interfaces/webpack-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ export type IWebpackStatsAssets = t.TypeOf<typeof RWebpackStatsAssets>;
const RWebpackStatsModuleBase = t.type({
// Chunk identifiers.
chunks: t.array(RWebpackStatsChunk),
// Full path to file on disk (with extra hash stuff if `modules` module).
// Full path to file on disk (with extra hash stuff if `modules` module and
// Full path to file on disk (with extra hash stuff if `modules` module and
// loader prefixes, etc.).
identifier: t.string,
// Estimated byte size of module.
// Estimated byte size of module.
size: t.number,
});

Expand Down Expand Up @@ -83,6 +82,21 @@ export const RWebpackStatsModuleSource = t.intersection([

export type IWebpackStatsModuleSource = t.TypeOf<typeof RWebpackStatsModuleSource>;

// ----------------------------------------------------------------------------
// Module: Orphaned code **source**
//
// Introduced in webpack5 as a stat field, ignore these as not in any chunk.
// See: https://webpack.js.org/configuration/stats/#statsorphanmodules
// ----------------------------------------------------------------------------
export const RWebpackStatsModuleOrphan = t.intersection([
RWebpackStatsModuleSource,
t.type({
orphan: t.boolean,
}),
]);

export type IWebpackStatsModuleOrphan = t.TypeOf<typeof RWebpackStatsModuleOrphan>;

// ----------------------------------------------------------------------------
// Module: Single "synthetic" module
//
Expand Down Expand Up @@ -117,6 +131,7 @@ export const RWebpackStatsModuleSynthetic = t.intersection([
RWebpackStatsModuleBase,
RWebpackStatsModuleWithName,
]);

export type IWebpackStatsModuleSynthetic = t.TypeOf<typeof RWebpackStatsModuleSynthetic>;

// ----------------------------------------------------------------------------
Expand Down
10 changes: 7 additions & 3 deletions src/plugin/duplicates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface ICompilation {
errors: Error[];
warnings: Error[];
getStats: () => {
toJson: () => IWebpackStats;
toJson: (opts: object) => IWebpackStats;
};
}

Expand Down Expand Up @@ -218,7 +218,7 @@ export class DuplicatesPlugin {

public apply(compiler: ICompiler) {
if (compiler.hooks) {
// Webpack4 integration
// Webpack4+ integration
compiler.hooks.emit.tapPromise("inspectpack-duplicates-plugin", this.analyze.bind(this));
} else {
// Webpack1-3 integration
Expand All @@ -228,7 +228,11 @@ export class DuplicatesPlugin {

public analyze(compilation: ICompilation, callback?: () => void) {
const { errors, warnings } = compilation;
const stats = compilation.getStats().toJson();
const stats = compilation
.getStats()
.toJson({
source: true // Needed for webpack5+
});

const { emitErrors, emitHandler, ignoredPackages, verbose } = this.opts;

Expand Down
4 changes: 2 additions & 2 deletions test/bin/inspectpack.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import execa = require("execa");

// Have to use transpiled bin to exec in Node.js
const IP_PATH = require.resolve("../../bin/inspectpack.js");
const SIMPLE_STATS = require.resolve("../fixtures/simple/dist-development-4/stats.json");
const DUP_ESM_STATS = require.resolve("../fixtures/duplicates-esm/dist-development-4/stats.json");
const SIMPLE_STATS = require.resolve("../fixtures/simple/dist-development-5/stats.json");
const DUP_ESM_STATS = require.resolve("../fixtures/duplicates-esm/dist-development-5/stats.json");

const exec = (args: string[]) => execa("node", [IP_PATH].concat(args), {
env: { ...process.env, FORCE_COLOR: "0" }
Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/config/versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
{ "WEBPACK_VERSION": "1" },
{ "WEBPACK_VERSION": "2" },
{ "WEBPACK_VERSION": "3" },
{ "WEBPACK_VERSION": "4" }
{ "WEBPACK_VERSION": "4" },
{ "WEBPACK_VERSION": "5" }
]
57 changes: 33 additions & 24 deletions test/fixtures/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
* Example usage (make sure to be in project root):
*
* ```sh
* $ export WEBPACK_VERSION=4; \
* $ export WEBPACK_VERSION=5; \
* WEBPACK_MODE=development \
* WEBPACK_CWD=../../test/fixtures/duplicates-esm \
* WEBPACK_CWD=../../test/fixtures/hidden-app-roots \
* NODE_PATH="${PWD}/node_modules/webpack${WEBPACK_VERSION}/node_modules:${PWD}/node_modules" \
* node test/fixtures/packages/webpack.js \
* --config ../../test/fixtures/config/webpack.config.js
Expand Down Expand Up @@ -39,14 +39,17 @@ const vers = process.env.WEBPACK_VERSION;
if (!vers) {
throw new Error("WEBPACK_VERSION is required");
}
const versNum = parseInt(vers, 10);

const cwd = process.env.WEBPACK_CWD;
if (!cwd) {
throw new Error("WEBPACK_CWD is required");
}

const outputPath = resolve(cwd, `dist-${mode}-${vers}`);
const webpack4 = {

// Webpack 4+
let configModern = {
mode,
devtool: false,
context: resolve(cwd),
Expand All @@ -72,7 +75,10 @@ const webpack4 = {
},
plugins: [
new StatsWriterPlugin({
fields: ["assets", "modules"]
fields: ["assets", "modules"],
stats: {
source: true // Needed for webpack5+
}
}),
DuplicatesPlugin ? new DuplicatesPlugin({
verbose: true,
Expand All @@ -81,36 +87,39 @@ const webpack4 = {
].filter(Boolean)
};

// Dynamically try to import a custom override from `CWD/webpack.config.js`
try {
const webpack = require(`webpack${vers}/lib`); // eslint-disable-line global-require
const override = require(resolve(cwd, "webpack.config.js")); // eslint-disable-line global-require
configModern = override(webpack, configModern, versNum);
} catch (err) {
if (err.code !== "MODULE_NOT_FOUND") {
throw err;
}
}

const webpack1Module = {
loaders: webpack4.module.rules.map((rule) => ({
loaders: configModern.module.rules.map((rule) => ({
test: rule.test,
loader: rule.use
}))
};

const webpackOld = {
devtool: webpack4.devtool,
context: webpack4.context,
entry: webpack4.entry,
output: webpack4.output,
// Webpack 2-3
const configLegacy = {
devtool: configModern.devtool,
context: configModern.context,
entry: configModern.entry,
output: configModern.output,
// TODO(66): Add minify thing here -- mode === "production",
// https://github.com/FormidableLabs/inspectpack/issues/66
module: vers === "1" ? webpack1Module : webpack4.module,
plugins: webpack4.plugins
module: versNum === 1 ? webpack1Module : configModern.module,
plugins: configModern.plugins,
resolve: configModern.resolve
};

// Choose appropriate version.
let config = vers === "4" ? webpack4 : webpackOld;

// Dynamically try to import a custom override from `CWD/webpack.config.js`
try {
const webpack = require(`webpack${vers}/lib`); // eslint-disable-line global-require
const override = require(resolve(cwd, "webpack.config.js")); // eslint-disable-line global-require
config = override(webpack, config);
} catch (err) {
if (err.code !== "MODULE_NOT_FOUND") {
throw err;
}
}
// eslint-disable-next-line no-magic-numbers
const config = versNum >= 4 ? configModern : configLegacy;

module.exports = config;
14 changes: 7 additions & 7 deletions test/fixtures/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
<body>
<h2>Test Fixture Loader</h2>
<p>
As a debugging helpder, this page provides a general loader into known paths to built fixtures.
As a debugging helper, this page provides a general loader into known paths to built fixtures.
</p>
<p>
Examples:
<ul>
<li>
<a href="./index.html?script=./simple/dist-development-4/bundle.js">
<code>./simple/dist-development-4/bundle.js</code>
<a href="./index.html?script=./simple/dist-development-5/bundle.js">
<code>./simple/dist-development-5/bundle.js</code>
</a>
</li>
<li>
<a href="./index.html?script=./moment-app/dist-development-4/bundle.js">
<code>./moment-app/dist-development-4/bundle.js</code>
<a href="./index.html?script=./moment-app/dist-development-5/bundle.js">
<code>./moment-app/dist-development-5/bundle.js</code>
</a>
</li>
<li>
Expand All @@ -27,8 +27,8 @@ <h2>Test Fixture Loader</h2>
</a>
</li>
<li>
<a href="./index.html?script=./multiple-chunks/dist-development-4/bundle-multiple.js">
<code>./multiple-chunks/dist-development-4/bundle-multiple.js</code>
<a href="./index.html?script=./multiple-chunks/dist-development-5/bundle-multiple.js">
<code>./multiple-chunks/dist-development-5/bundle-multiple.js</code>
</a>
</li>
</ul>
Expand Down
13 changes: 3 additions & 10 deletions test/fixtures/loaders/src/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@

/* eslint-disable no-console */
/* globals global */

import text from "./hello.txt";
import style from "./style.css";

// Use expose loader to make global
require("expose-loader?BunBun!./bunny"); // eslint-disable-line import/no-unresolved
// Legacy: just require a file (gave up on `expose-loader` global in webpack5
// upgrade).
require("./bunny");

const hello = () => "hello world";

console.log("hello", hello());
console.log("text", text);
console.log("style", style.toString());

let root = typeof window !== "undefined" && window;
if (!root && typeof global !== "undefined") {
root = global;
}

console.log("global", root.BunBun);
Loading

0 comments on commit b75d9f2

Please sign in to comment.