styleguidist / react-styleguidist

Isolated React component development environment with a living style guide
https://react-styleguidist.js.org/
MIT License
10.84k stars 1.44k forks source link

Performance improvement ideas #258

Open sapegin opened 7 years ago

sapegin commented 7 years ago

Just a list of things and ideas that worth trying to improve compilation speed and reduce bundle size:

Non-working ideas:

aaronjensen commented 7 years ago

We're using HardSourceWebpackPlugin with styleguidist and it seems to work well. It only really helps on the first build, not subsequent builds as far as I can tell.

happypack would be great in theory, but I worry about its lack of compatibility for some things.

sapegin commented 7 years ago

They say:

…the first build will take the normal amount of time. The second time, the build time will be greatly reduced.

Could you share your config? It looks quite complicated.

aaronjensen commented 7 years ago
let configName = 'styleguide'

if (process.argv.includes('server')) {
  // Use different cache for server
  configName = 'styleguide-server'
}

// ...      

      new HardSourceWebpackPlugin({
        cacheDirectory: path.join(__dirname, 'tmp/hard-source', configName),
        recordsPath: path.join(__dirname, 'tmp/hard-source', configName, 'records.json'),
        environmentPaths: {
          root: process.cwd(),
          directories: ['node_modules'],
          files: [
            'package.json',
            'yarn.lock',
            'styleguide.config.js',
          ],
        },
      })
aaronjensen commented 7 years ago

And yes, by "second time" they're not talking about subsequent builds within a single watch. I was differentiating between dev watch and just building from the command line. HSWP helps with the first build of a watch and every build from the command line.

n1313 commented 7 years ago

This is probably more about bundle size than performance, but those things sometimes come hand in hand. How about using lodash modules instead of importing the entire lodash package? I have run my bundle through webpack-bundle-analyzer and I see that the biggest parts of styleguidist are lodash, buble and acorn. I don't know if there's anything that can be done with buble or acorn, but replacing lodash with lodash modules could be done, I think?

sapegin commented 7 years ago

@n1313

  1. We were importing the whole Lodash only to make it available in examples as _. We’re not doing that anymore in the upcoming 5.0.0 — https://github.com/styleguidist/react-styleguidist/issues/249

  2. Nothing we can do about Buble and Acorn (Acorn is a Buble’s dependency). It’s already much much smaller than babel-standalong that we used to use before.

sapegin commented 7 years ago

Actually we can do something with Buble but not for all users. We can make transformer replacable and if you’re using only latest browsers and don’t care about JSX, you could just replace it with nothing.

sapegin commented 7 years ago

Trying babel-preset-env and babel-react-optimize but looks like our codebase is too small to have any benefits:

Base:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 628 kB
Gzipped:  183 kB (29.08%)
lib: 139.34kb

babel-preset-env:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 628 kB
Gzipped:  183 kB (29.08%)
lib: 139.34kb

babel-react-optimize:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 635 kB
Gzipped:  183 kB (28.81%)
lib: 189.30kb

babel-preset-env + babel-react-optimize:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 635 kB
Gzipped:  183 kB (28.81%)
lib: 177.29kb

(lib is the size of all transpiled JS files.)

.babelrc:

{
    "presets": [
        "react",
        ["env", {
            "targets": {
                "browsers": ["last 2 versions", "not ie < 11", "not ie_mob < 11"]
            }
        }]
    ],
    "plugins": [
        "transform-class-properties",
        "transform-object-rest-spread"
    ],
    "env": {
        "production": {
            "presets": ["react-optimize"]
        }
    }
}
n1313 commented 7 years ago

Is this for v5 branch?

sapegin commented 7 years ago

@n1313 The numbers in the latest comment? Yes. But I won’t commit it most probably since there’s no improvements.

n1313 commented 7 years ago

Would you mind trying doing the same in v4? I wonder if it will be equally unimpressive.

sapegin commented 7 years ago

Could try later.

sapegin commented 7 years ago

Yeah, no change for the master branch too:

Base:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 2.26 MB
Gzipped:  480 kB (21.21%)

babel-preset-env:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 2.26 MB
Gzipped:  480 kB (21.21%)

babel-preset-env + babel-react-optimize:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 2.26 MB
Gzipped:  480 kB (21.21%)
n1313 commented 7 years ago

Wait a second, you've dropped bundle size from 2.26 MB in v4 to 635 kB in v5? Wow.

sapegin commented 7 years ago

@n1313 I’ve fixed Uglify and removed Lodash. Maybe something else ;-)

sapegin commented 7 years ago

Another comparison.

Webpack 1:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 626 kB
Gzipped:  182 kB (29.02%)

Webpack 2:

❯ gz examples/basic/styleguide/build/bundle.js
Original: 629 kB
Gzipped:  182 kB (28.96%)

No improvement in Webpack 2 probably because we should disable ES6 modules transformation to make tree shaking work. In that case to support both Webpack 1 and 2 we should build two sets of JS: with and without modules.

But I’m not sure it will help in case of our own code since we’re using at least most of it. So, yeah, I’m actually interested how to make it work with dependencies.

aaronjensen commented 7 years ago

@sapegin Did you set useBuiltIns to true? Also, the browser support matrix would probably make a difference. And yes, for webpack 2, modules should be false. I found a 10-20k difference in our file when I used it, but it wasn't enough to justify possibly picking the wrong range for our app.

sapegin commented 7 years ago

@aaronjensen No, will it help if I don’t use babel-polyfill? Or will I have to use it? For tree shaking we’ll need to transpile two sets of files (because we still support Webpack 1) and I think it’s not worth it. It also breaks UglifyJS because it doesn’t support ES6.

aaronjensen commented 7 years ago

useBuildIns requires babel-polyfill, it just trims down what it actually emits. Soon it will trim down even more.

For tree shaking we’ll need to transpile two sets of files (because we still support Webpack 1)

This is common, hence jsnext:main in package.json.

That said, I wasn't aware you were talking about a build step prior to packaging, is that what you're talking about? In that case, I don't think you should be polyfilling at all. You definitely shouldn't be uglifying, that's the responsibility of the end user/during the actual styleguide build post webpack.

sapegin commented 7 years ago

@aaronjensen It’s a bit more complicated than that ;-)

  1. We transpile all Styleguidist to ES5 before publishing to npm (in upcoming 5.0.0) to get rid of babel-loader.
  2. We can’t use jsnext:main for that because we importing local files, not package. So we’ll need to transpile to copies and somehow decide what to use in Weback config. Not sure it‘s worth it.
  3. We should Uglify by default all style guide bundle, not our own source. Users shouldn’t care about that.
  4. We don’t use any polyfills now.
jiayihu commented 7 years ago

I suggest also trying optimize-js for styleguide builds to improve time to first render. I tried it with a project where the bundle.js is about 2.0MB and noticed some improvements in the Timeline:

Avarage DOMContentLoaded time without optimize-js: 3.11s Avarage DOMContentLoaded time with optimize-js: 2.73s

Not overkill, but still useful speed gain I believe.

okonet commented 6 years ago

I think that SSR + lazy loading should give the ultimate perf boost if we're talking about loading times.

I've tried DllPluging on several projects and didn't see any improvements in build times ¯_(ツ)_/¯

okonet commented 6 years ago

Related #330

FDiskas commented 2 years ago

The idea would be to go away from webpack and start using something more modern. I know that this will brings a lot of breaking changes but - it's time to move forward. Good candidates are simple rollup or wrapper vitejs or another builder like parcel