Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[performance] use JSON.parse(jsonSource) for JSON modules #9349

Merged
merged 2 commits into from Jul 2, 2019

Conversation

@gfx
Copy link
Contributor

gfx commented Jul 2, 2019

Use JSON.parse(jsonSource) for JSON modules instead of object literals.

This is an implementation of the idea that comes from https://v8.dev/blog/cost-of-javascript-2019

As long as the JSON string is only evaluated once, the JSON.parse approach is much faster compared to the JavaScript object literal, especially for cold loads.

The article is written by the V8 team, but it should be true for all the JavaScript engines because JSON is much simpler than JavaScript.

NOTE: I didn't add an option to enable/disable this feature because users can easily use json-loader that converts JSON to JavaScript.

What kind of change does this PR introduce?

A performance optimization.

Did you add tests for your changes?

No. This PR does not change the behavior, but I've tested it on my production code that boosts ~20% of "loading" time on Chrome 75 in my bundle.js that includes over 1MiB of JSON objects.

Does this PR introduce a breaking change?

No.

What needs to be documented once your changes are merged?

No. It's just an implementation detail.


FYI you can try the implementation without patching webpack:

// optimized-json-loader.js
"use strict";

module.exports = function loadJsonModule(source) {
  if (typeof source !== "string") {
    throw new Error("Unexpected source type: " + typeof source);
  }
  const object = JSON.parse(source);
  const jsonSource = JSON.stringify(object);

  // cf. https://v8.dev/blog/cost-of-javascript-2019
  // > As long as the JSON string is only evaluated once, the JSON.parse approach is
  // > much faster compared to the JavaScript object literal, especially for cold loads.
  return `module.exports = JSON.parse(${JSON.stringify(jsonSource)});`;
};
// in webpack.config.js
const config = {
  // ...
  module: {
    rules: [
      {
        test: /\.json$/,
        type: "javascript/auto",
        use: {
          loader: path.resolve(__dirname, "./optimized-json-loader.js"),
        },
      },
    ],
   // ...
 }
};

(added on 2019/07/09)

To disable this feature in order to, for example, measure the performance, use the good old json-loader module:

const config = {
  // ...
  module: {
    rules: [
      {
        test: /\.json$/,
        type: "javascript/auto",
        use: {
          loader: "json-loader",
        },
      },
    ],
   // ...
 }
};
https://v8.dev/blog/cost-of-javascript-2019
> As long as the JSON string is only evaluated once, the JSON.parse approach is much faster compared to the JavaScript object literal, especially for cold loads.
@webpack-bot

This comment has been minimized.

Copy link
Contributor

webpack-bot commented Jul 2, 2019

For maintainers only:

  • This need to be documented (issue in webpack/webpack.js.org will be filed when merged)
@webpack-bot

This comment has been minimized.

Copy link
Contributor

webpack-bot commented Jul 2, 2019

Thank you for your pull request! The most important CI builds succeeded, we’ll review the pull request soon.

@gfx gfx changed the title use JSON.parse(jsonSource) for JSON modules [performance] use JSON.parse(jsonSource) for JSON modules Jul 2, 2019
@sokra
sokra approved these changes Jul 2, 2019
@sokra sokra closed this Jul 2, 2019
@sokra sokra reopened this Jul 2, 2019
@sokra sokra merged commit 6dbae4b into webpack:master Jul 2, 2019
28 checks passed
28 checks passed
codecov/changes/basic No unexpected coverage changes found.
Details
codecov/changes/integration No unexpected coverage changes found.
Details
codecov/changes/unit No unexpected coverage changes found.
Details
codecov/patch/basic 100% of diff hit (target 90%)
Details
codecov/patch/integration 100% of diff hit (target 90%)
Details
codecov/patch/unit Coverage not affected when comparing bf3e869...1cc9f87
Details
codecov/project/basic 86.96% (+<.01%) compared to bf3e869
Details
codecov/project/integration 91.39% (+<.01%) compared to bf3e869
Details
codecov/project/unit 100% (target 0%)
Details
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
licence/cla Contributor License Agreement is signed.
Details
security/snyk - package.json (sokra) No new issues
Details
webpack.webpack Build #20190702.4 succeeded
Details
webpack.webpack (Linux node-10) Linux node-10 succeeded
Details
webpack.webpack (Linux node-12) Linux node-12 succeeded
Details
webpack.webpack (Linux node-6) Linux node-6 succeeded
Details
webpack.webpack (Linux node-8) Linux node-8 succeeded
Details
webpack.webpack (Windows node-10) Windows node-10 succeeded
Details
webpack.webpack (Windows node-12) Windows node-12 succeeded
Details
webpack.webpack (Windows node-6) Windows node-6 succeeded
Details
webpack.webpack (Windows node-8) Windows node-8 succeeded
Details
webpack.webpack (basic) basic succeeded
Details
webpack.webpack (lint) lint succeeded
Details
webpack.webpack (macOS node-10) macOS node-10 succeeded
Details
webpack.webpack (macOS node-12) macOS node-12 succeeded
Details
webpack.webpack (macOS node-6) macOS node-6 succeeded
Details
webpack.webpack (macOS node-8) macOS node-8 succeeded
Details
@sokra

This comment has been minimized.

Copy link
Member

sokra commented Jul 2, 2019

Thanks

@gfx gfx deleted the gfx:json_module_as_json branch Jul 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.