Help us understand the problem. What is going on with this article?

Nuxt.jsのビルド時間を短縮する為に頑張った話

やりたい事

  • Nuxt.jsのビルド時間を短縮したい
  • JSのファイルサイズを軽くしたい

やった事

  • 1.Webpack Bundle Analyzerを使って、現状のファイルサイズを把握。
  • 2.その中でどのファイルがネックになっているか調査する。
  • 3.リファクタリングする。 ※今回は一部のみ

0.各キーワード説明

Webpack Bundle Analyzerとは?

下記を可視化してくれる。
- webpackの速度改善の為、遅いloaderやpluginを知りたい
- バンドルファイルのサイズを減らしたいので、バンドルファイル内の各パッケージがどのくらいの容量を占めているか知りたい。

参考:https://github.com/webpack-contrib/webpack-bundle-analyzer

1.Webpack Bundle Analyzerを使って、現状のファイルサイズを把握。

$ yarn build --analyze

スクリーンショット 2019-12-16 23.47.31.png

2.その中でどのファイルがネックになっているか調査する。

スクリーンショット 2019-12-16 23.52.50.png

  • ①Chart.jsが重い
  • ②moment.jsが重い
    • localeが無駄に多い
  • ③lodash.jsが重い

3.リファクタリングする。

  • ①Chart.jsが重い
    • vue-chart.jsの中で使われているので、外すのは難しそうだった。

  "dependencies": {
    "bootstrap": "^3.4.1",
    "bootstrap-social": "^5.1.1",
    "bootstrap-vue": "^2.0.0-rc.24",
    "chart.js": "^2.8.0",
    "chosen-js": "^1.8.5",
    "ckeditor": "^4.11.4",
    "clipboard": "^2.0.4",
    "datatables": "^1.10.13",
    "datatables-all": "^1.10.13",
    "firebase": "^6.0.1",
    "font-awesome": "^4.7.0",
    "hchs-vue-charts": "^1.2.8",
    "icheck": "^1.0.2",
    "ionicons": "^4.5.8",
    "jquery-datetimepicker": "^2.5.21",
    "jquery-ui-dist": "^1.12.1",
    "jquery.flot": "^0.8.3",
    "luxon": "^1.15.0",
    "moment": "^2.24.0",
    "sass": "^1.20.1",
    "sass-loader": "^7.0.1",
    "select2": "^4.0.7",
    "sweetalert2": "^8.11.6",
    "turbolinks": "^5.0.3",
    "vue-chartjs": "^3.4.2",
    "vue-datetime": "^1.0.0-beta.10",
    "vue-js-modal": "^1.3.31",
    "vue-nl2br": "^0.1.1",
    "vue-resource": "^1.3.4",
    "vue-spinner": "^1.0.3",
    "vue-spinner-component": "^1.0.5",
    "vuex": "^3.1.1",
    "weekstart": "^1.0.0",
    "yubinbango": "yubinbango/yubinbango"
  },

  • ②moment.jsが重い
    • nuxt.config.jsにmomentの設定を追加

module.exports = {
  mode: 'spa',

// 省略

  build: {
    parallel: true,

    /*
     * Run ESLint on save
     */
    extend (config, { isDev, isClient }) {
      // クライアントのバンドルの Webpack 設定のみを拡張する
      if (isClient) {
        config.devtool = '#source-map'
      }

      if (isDev && isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/,
        })

        const vueLoader = config.module.rules.find(
          ({ loader }) => loader === 'vue-loader')
        const { options: { loaders } } = vueLoader || { options: {} }

        if (loaders) {
          for (const loader of Object.values(loaders)) {
            changeLoaderOptions(Array.isArray(loader) ? loader : [loader])
          }
        }

        config.module.rules.forEach(rule => changeLoaderOptions(rule.use))

        // For faster build. Use hard-source-webpack-plugin.
        const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
        config.plugins.push(new HardSourceWebpackPlugin())
      }
    },
      // ここを変更
      vendeer: ['moment'],
      plugins: [
          new MomentLocalesPlugin({
              localesToKeep: ['es-us', 'ja']
          })
      ]
  },
}
  • ③lodash.jsが重い
    • 現状、ディープコピーの箇所にしかlodash.jsが使われていなかった
<script>
import { mapActions, mapGetters } from 'vuex'
import cloneDeep from 'lodash'

export default {
  name: 'agent',
  layout: 'administrator/default',
  data () {
    return {
     // 省略
      },
    }
  },
  async created () {
    // 省略
  },
  computed: {
    // 省略
  },
  methods: {
    async setProgrammingCategory () {

      let programmingCategory = this.programmingCategories.find(programmingCategory => Number(programmingCategory.id) === Number(this.programmingCategoryId))


      if (!programmingCategory) {
        this.$nextTick(() => this.$nuxt.$loading.start())
        try {
          await this.fetchProgrammingCategories()
        } catch (e) {
          console.log(e.message)
          return
        } finally {
          this.$nuxt.$loading.finish()
        }
        programmingCategory = this.programmingCategories.find(programmingCategory => Number(programmingCategory.id) === Number(this.programmingCategoryId))
        if (!programmingCategory) {
          this.$router.push('/errors/404')
        }
      }

      this.formData = cloneDeep(programmingCategory)
    },
    async update () {
      // 省略
    },
    ...mapActions('administrator', ['fetchProgrammingCategories', 'updateProgrammingCategory']),
  },
}
</script>
  • 修正点
    lodashをimport _ from 'lodash'のように読み込んでしまうと、全てのlodash関数などがbundleされてしまいます。 それを回避するため、使用する関数のみをimportするように変更します。
<script>
import cloneDeep from 'lodash/cloneDeep'


</script>

改善結果

改善前

スクリーンショット 2019-12-17 0.15.06.png

改善後

lodashとmoment.jsはほぼ消えた!
スクリーンショット 2019-12-17 0.15.15.png

改善前

スクリーンショット 2019-12-17 0.16.05.png

改善後

約1MB軽量化!!
スクリーンショット 2019-12-17 0.16.15.png

まとめ

  • ビルドの高速化するにあたって、moment.jsやlodash.jsが重くなるのはよくありそう
  • 補足としては、そもそもmoment.jsよりday.jsの方が軽いので、そっちを使うと良いらしい!

参考記事

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした