Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
780 views
in Technique[技术] by (71.8m points)

vue.js - Building deeply nested html with vue-cli takes forever

I found that vue-cli (2.9.6, but 3.0.0 beta* has the same issue) 's building process takes forever once the template's html gets relativelly deep.

For example, I just added some divs to App.vue which is pre-included:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div><div><div><div></div></div></div></div>
    <HelloWorld/>
  </div>
</template>

which doesn't take so long.

But once it gets this:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
    <HelloWorld/>
  </div>
</template>

then the building process takes forever, and I believe that the nest of this depth isn't so uncommon.

How should I deal with this problem?

EDIT(Details)

It seems that the problem might be environment specific, so here are the details.

This problem can be reproduced with these environments at least:

  • macOS High Sierra on Mac mini (Late 2014)
  • Ubuntu 18.04 on Dell XPS 13

and node and npm version are:

node --version
# prints
v8.9.4
# and
npm version
# prints
{ npm: '6.1.0',
  ares: '1.10.1-DEV',
  cldr: '31.0.1',
  http_parser: '2.7.0',
  icu: '59.1',
  modules: '57',
  nghttp2: '1.25.0',
  node: '8.9.4',
  openssl: '1.0.2n',
  tz: '2017b',
  unicode: '9.0',
  uv: '1.15.0',
  v8: '6.1.534.50',
  zlib: '1.2.11' }

With these, I've retried the followings on my Mac:

npm uninstall -g vue-cli
npm install -g vue-cli
vue init webpack divnest
# then some Enter keys - everything is default
cd divnest

Then, open up App.vue and put many divs:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
    <router-view/>
  </div>
</template>

(Since I used the default settings here, <router-view/> is included unlike the original post, but should not be the problem.)

And finally,

npm run dev

which takes forever - specifically, the process stops at this point:

 13% building modules 28/31 modules 3 active ...myname/Documents/divnest/src/App.vue

In the case of

npm run build

, the process stops at this point:

> [email protected] build /Users/myname/Documents/divnest
> node build/build.js

Hash: 483ebabc54d5aed79fd7
Version: webpack 3.12.0
Time: 13742ms
                                                  Asset       Size  Chunks             Chunk Names
               static/js/vendor.7fed9fa7b7ba482410b7.js     112 kB       0  [emitted]  vendor
                  static/js/app.f1ebca7a6e0ec0b7ebdf.js      12 kB       1  [emitted]  app
             static/js/manifest.2ae2e69a05c33dfc65f8.js  857 bytes       2  [emitted]  manifest
    static/css/app.30790115300ab27614ce176899523b62.css  432 bytes       1  [emitted]  app
static/css/app.30790115300ab27614ce176899523b62.css.map  828 bytes          [emitted]  
           static/js/vendor.7fed9fa7b7ba482410b7.js.map     553 kB       0  [emitted]  vendor
              static/js/app.f1ebca7a6e0ec0b7ebdf.js.map    23.3 kB       1  [emitted]  app
         static/js/manifest.2ae2e69a05c33dfc65f8.js.map    4.97 kB       2  [emitted]  manifest
                                             index.html  509 bytes          [emitted]  

  Build complete.

  Tip: built files are meant to be served over an HTTP server.
  Opening index.html over file:// won't work.

 94% asset optimization 

and if I let it go, it takes... 1155409ms!!!!

 DONE  Compiled successfully in 1155409ms                                                        13:35:34

 I  Your application is running here: http://localhost:8080

MORE EDIT

As @tony19 pointed out, prettier is the likely suspect. Following the advice, I've tried some patterns with Ubuntu 18.04 (not Mac because Mac isn't here right now, sorry) and my results are:

  • vue-cli 2.9.6 + npm run dev - hang
  • vue-cli 2.9.6 + npm run build - 6 secs (This is so confusing. What was the 1 million seconds above!? Maybe reinstalling vue-cli owes the change?)
  • vue-cli 3.0.0-beta16 + vue serve - hang (as opposed to @tony19's report)
  • vue-cli 3.0.0-beta16 + vue build - 5 secs

EVEN MORE EDIT

So, it seems that this is definitely caused by prettier. https://github.com/prettier/prettier/issues/1250 is the original issue that addressed this problem and the dev team thought that https://github.com/prettier/prettier/pull/2259 fixed it, but the reality is that it couldn't handle my case, as @tony19 shows it on https://github.com/prettier/prettier/issues/4672 . Oh well.

"SOLUTION"

I ended up doing this - following @tony19's report, changing /node_modules/vue-loader/lib/template-compiler/index.js lines 78:81

if (!isProduction) {
  code = prettier.format(code, { semi: false })
}

to

// if (!isProduction) {
//   code = prettier.format(code, { semi: false })
// }

thus the problem is solved. Thank you frontend, thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I can reproduce the performance issue as you described (macOS High Sierra 10.13.4, Node 8.9.4 and 9.11.1). The issue also occurs with a newly created vue-cli 3.x project.

The hang is actually happening in prettier, called from vue-loader's template compiler. The nested <div>s are converted into JavaScript by vue-loader, and that becomes the following snippet:

var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{attrs:{"id":"app"}},[_c('img',{attrs:{"src":require("./assets/logo.png")}}),_vm._v(" "),_c('router-view'),_vm._v(" "),_vm._m(0)],1)}
var staticRenderFns = [function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div',[_c('div')])])])])])])])])])])])])])])])])])])])])])])])])}]

vue-loader passes this long string to prettier, which takes about 159 seconds to process. The cause of the bug is the deeply nested function calls that create the divs. I've reported this bug in prettier (Issue 4672).

In the meantime, I recommend refactoring your HTML to avoid deep nesting. If you need to stick with the old template, you could workaround the issue by building in production mode, as vue-loader skips prettier for production builds:

NODE_ENV=production npm run dev

UPDATE vue-loader v15.5.0 adds the prettify option to allow disabling prettier (update to the latest version of @vue/cli to ensure your vue-loader is current with the new option). You can use this option as follows:

  1. Add vue.config.js (if it doesn't exist already) to the root of your project.

  2. Edit the file to include:

    module.exports = {
      chainWebpack: config => {
        config.module
          .rule('vue')
          .use('vue-loader')
            .loader('vue-loader')
            .tap(options => {
              options.prettify = false
              return options
            })
      }
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...