JavaScript
reactjs
webpack
React
create-react-app

webpackでbuildされるファイルがデカすぎてつらい時(分割されすぎてつらい時も後述)

:writing_hand: Code-Splitting

Note:
The dynamic import() syntax is a ECMAScript (JavaScript) proposal not currently part of the language standard. It is expected to be accepted in the near future.

setup
npx create-react-app my-app
cd my-app
# 邪魔 
rm src/*.css src/App.test.js src/logo.svg src/registerServiceWorker.js
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
App.js
import React, { Component } from "react";

class App extends Component {
  render() {
    return <div />;
  }
}

export default App;
何もしてない状態のbuild後のサイズ
yarn build
# ...
# File sizes after gzip:
#  36.22 KB  build/static/js/main.cb06ce91.js
色々と入れてゆく
yarn add ramda lodash underscore
App.js
import React, { Component } from "react";
import * as R from "ramda";
import * as _ from "lodash";
import * as us from "underscore";

class App extends Component {
  render() {
    return (
      <div>
        {R.always("aaaa")}
        {_.join(["a", "b", "c"], "~")}
        {us.now()}
      </div>
    );
  }
}

export default App;
するとbuild後のファイルがクソデカになっていく
yarn build
# ...
# File sizes after gzip:
#  75.55 KB (+39.52 KB)  build/static/js/main.5c0f838b.js
build後のファイルを分割する手法として動的インポートが提案されている
// before
import { add } from './math';

console.log(add(16, 26));

// after
import("./math").then(math => {
  console.log(math.add(16, 26));
});
公式が推奨しているライブラリを使ってみる
yarn add react-loadable
index.js
import React from "react";
import ReactDOM from "react-dom";
import Loadable from "react-loadable";

const LoadableApp = Loadable({
  loader: () => import("./App"),
  loading: () => <div>Loading...</div>
});

ReactDOM.render(<LoadableApp />, document.getElementById("root"));
mainの減量成功
yarn build
#File sizes after gzip:
# 40.29 KB              build/static/js/0.ab70241c.chunk.js
# 37.81 KB (-37.74 KB)  build/static/js/main.0a2572c6.js
分割場所は一旦rootでやっておけばよさそう
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable';

const Loading = () => <div>Loading...</div>;

const Home = Loadable({
  loader: () => import('./routes/Home'),
  loading: Loading,
});

const About = Loadable({
  loader: () => import('./routes/About'),
  loading: Loading,
});

const App = () => (
  <Router>
    <Switch>
      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
    </Switch>
  </Router>
);
因みに分割されるのが逆に嫌な時はwebpackの設定で制御可能
yarn eject
yarn
config/webpack.config.prod.js
...
plugins: [
    ...,
    new webpack.optimize.LimitChunkCountPlugin({
      maxChunks: 1
    }),
  ]
...
動的インポートをしていても分割されない
yarn build
#File sizes after gzip:
# 76.97 KB (+39.16 KB)  build/static/js/main.7748b8f8.js

:moyai: 「...2MBのJSファイルは流石にやりすぎましたわ」