LoginSignup
1
1

More than 3 years have passed since last update.

[Tips] Webpackでビルドしたバンドルファイルのサイズを減らす

Last updated at Posted at 2020-05-21
1 / 21

webpack-bundle-analyzerでモジュールのサイズを可視化する

image (4).png


lodash.jsのサイズを減らす

import _ from 'lodash';
// _.clone(...)

全てのlodash関数などがbundleされてしまいます。


→使用する関数のみをimportするように変更します

import {keys, clone} from 'lodash';

バンドルファイルのサイズが変わらない :disappointed:


Why? :thinking:


import {keys, clone} from 'lodash';

// ビルドした後

var lodash = require('lodash');
var keys = lodash.keys;
var clone = lodash.clone;

解決:default style imports

import keys from 'lodash/keys';
import clone from 'lodash/clone';

メリット:使用する関数のみがimportされる
デメリット:コードが長くなる→import {keys, clone}を使いたい


transform-importsプラグイン導入

{
  "plugins": [
    ["transform-imports", {
      "my-library\/?(((\\w*)?\/?)*)": {
        "transform": "my-library/${1}/${member}",
        "preventFullImport": true
      }
    }]
  ]
}

 ["transform-imports", {
  "react-bootstrap": { 
    "transform": "react-bootstrap/lib/${member}", 
    "preventFullImport": true 
  }, 
  "lodash": { 
    "transform": "lodash/${member}", 
    "preventFullImport": true 
  } 
}]

import {keys, clone}を使えるようになる


moment.jsのサイズを減らす

  new webpack.ContextReplacementPlugin(
     /moment[/\\]locale$/, 
     /ja/ 
  )
require('./locale/' + name + '.js')

Dynamic Import

import data from '../data'
// ...
if(condition) {
  run(data)
}
// ...

↓↓↓↓
使う時のみファイルをimportする

if(condition) {
  import('../data').then(({ default: data}) => {
    run(data)
  })
}

chunkファイル自動作成
スクリーンショット 2020-05-21 23.51.55.png


ClassComponent → Functional Component(React)

// Functional Component
const MyComponent = props => <div>{props.name}</div>;
// Class Component
class MyComponent extends React.Component {  
  render() {  
    return <div>{this.props.name}</div>;  
  }  
}

ES5にビルドした後

// Functional Component - 133byte
var MyComponent = function MyComponent(props) {
  return /*#__PURE__*/React.createElement("div", null, props.name);
};
// Class Component - 3.5kb
function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

var MyComponent = /*#__PURE__*/function (_React$Component) {
  _inherits(MyComponent, _React$Component);
  var _super = _createSuper(MyComponent);
  function MyComponent() {
    _classCallCheck(this, MyComponent);
    return _super.apply(this, arguments);
  }
  _createClass(MyComponent, [{
    key: "render",
    value: function render() {
      return /*#__PURE__*/React.createElement("div", null, this.props.name);
    }
  }]);
  return MyComponent;
}(React.Component);

Functional Componentを使ったら 3.5kbから133byteになる


Webpack3 → Webpack4

ビルド時間: 10%アップ
ファイルのサイズ: あまり変わらない


結果

imgonline-com-ua-twotoone-bO5ErAVOi4IW.jpg


imgonline-com-ua-twotoone-8ZCCMhvQFcu5PAI.jpg


image (2).png


ご清聴ありがとうございました


1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1