Building deeply nested html with vue-cli takes forever
I had similar issues with vue-cli 3.1.1 (TypeScript + SCSS) and Bootstrap (which by default requires some nesting). Example structure:
<template>
<div class="container">
<div class="row">
<div class="col-12">
<div class="card-deck">
<div class="card">
<div class="card-body">
<div class="accordion">
<div class="card">
<div class="card-header">
...
</div>
<div class="collapse">
<div class="card-body">
<div class="row">
<div class="col-12 form-group">
<label>...</label>
<div class="dropdown">
<button class="custom-select" type="button" data-toggle="dropdown">{{someValue}}</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" :data-key="somekey1" @click="onClickMethod">value1</a>
<a class="dropdown-item" href="#" :data-key="somekey2" @click="onClickMethod">value2</a>
...
needed ~12 seconds to compile 400+ lines of code (template + TypeScript + SCSS). After removing:
:data-key="somekey1" @click="onClickMethod"
:data-key="somekey2" @click="onClickMethod"
the code needed ~5-6 seconds to compile. After moving the code to custom component (and some TypeScript code from Vue component to Helper.ts file):
<template>
<div class="container">
<div class="row">
<div class="col-12">
<div class="card-deck">
<div class="card">
<div class="card-body">
<div class="accordion">
<div class="card">
<div class="card-header">
...
</div>
<div class="collapse">
<div class="card-body">
<SubComponent/>
it needs ~700ms to compile (one main component and two additional sub-components, each file having less than 100 lines of code + Helper.ts having exactly 97 lines of code).
So if you suffer from poor npm run serve
performance, try sub-components first, I didn't noticed much difference in compile time while invoking npm run build
so I assume (maybe incorrectly) that this problem is also caused by code prettifier which is enabled for serve
but disabled for build
(TSLint is not invoked on save action so it does not affect npm run serve
in my case).
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 div
s. 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:
Add
vue.config.js
(if it doesn't exist already) to the root of your project.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 }) } }
Update 2019
Recently vue-loader
added a flag in their options in order to disable prettier
also during development.
Just add prettify: false
to your vue-loader
options.
https://vue-loader.vuejs.org/options.html#prettify
Notice: Just make sure you have the latest vue-loader version