4

I have bitten the bullet and switched over to a modular approach to my Vue.js, using vue-cli and Webpack. There's been a bit of a learning curve with restructuring my application into single file components, but I have largely been getting there. I have now, though, run into a very puzzling problem. I have a reasonably complex component, ProductDetail, which uses a few child components. As soon as I add one of them, called TabPage (by including the import line and adding it to the components property), compilation hangs (and if I restart 'npm run dev' it similarly hangs on startup, before getting to the point where it's serving pages). The other 6 components don't cause this problem at all.

Now the bizarre thing is that this component, TabPage, can be effectively empty, being nothing more than a template outputting an empty div, and the problem still occurs, so it can't be a problem with this component (besides which everything was working in the version of the application before I switched to using vue-cli). And it's only this component, nothing else causes the issue.

So is there some means of debugging the compilation process so that I can see precisely where the problem is occurring?

For what it's worth, here's the ProductDetail component (with the methods removed, to bring it all down to a size StackOverflow is happy with):

<template> <div class="container edit-product"> <ul class="nav nav-tabs"> <tab-link page="Product"></tab-link> <tab-link page="Pricing"></tab-link> <tab-link page="History"></tab-link> <tab-link page="Shop"></tab-link> </ul> <div class="tab-content"> <tab-page page="Product"> <form @submit.prevent.stop class="edit-form"> <div class="form-fields"> <common-header :product="this.product" :error="this.error"></common-header> <div class="row"> <cell :cols="8"><text-field name="name" v-model="product.name"/></cell> <cell :cols="1"><text-field name="pack" v-model.number="product.pack" format="numeric"/></cell> <cell :cols="3"><text-field name="size" v-model="product.size"/></cell> </div> <div class="row"> <cell :cols="2"> <text-field name="code" v-model="product.code" :attrs="{maxlength: 5}"> <button slot="after" type="button" class="btn btn-sm fld-btn" @click="seeExisting">Existing</button> </text-field> </cell> <cell :cols="2"> <text-field name="supplierCode" v-model="product.supplierCode"> <button slot="after" type="button" class="btn btn-sm fld-btn" @click="selectSupplier">Select</button> </text-field> </cell> <cell :cols="5"> <text-field name="supplierName" v-model="product.supplierName" :attrs="{disabled: true}"/> </cell> <cell :cols="3"> <text-field label="Supplier's Product Code" name="supplierProdCode" v-model="product.supplierProdCode"/> </cell> </div> <div class="row"> <cell :cols="6"> <text-field name="categorization" v-model="categorization" :attrs="{disabled: true}"> <button slot="before" type="button" class="btn btn-sm fld-btn" @click="categorize">Set</button> </text-field> </cell> <cell :cols="6"> <text-field name="tradeName" v-model="product.tradeName"/> </cell> </div> <div class="row"> <cell :cols="12"> <checkbox-field inline="true" name="readyPacked" label="Ready-Packed" v-model="product.readyPacked"></checkbox-field> <checkbox-field inline="true" name="shop" v-model="product.shop"></checkbox-field> <checkbox-field inline="true" name="organic" v-model="product.organic"></checkbox-field> <checkbox-field inline="true" name="withSugar" v-model="product.withSugar"></checkbox-field> <checkbox-field inline="true" name="stockControlled" label="Stock-controlled" v-model="product.stockControlled"></checkbox-field> <checkbox-field inline="true" name="vegan" v-model="product.vegan"></checkbox-field> <checkbox-field inline="true" name="fairTrade" v-model="product.fairTrade"></checkbox-field> <checkbox-field inline="true" name="glutenFree" label="Gluten-free" v-model="product.glutenFree"></checkbox-field> </cell> </div> <div class="row"> <cell :cols="1"> <text-field name="aisle" v-model="product.aisle" :attrs="{maxlength: 2}" format="uppercase"/> </cell> <cell :cols="1"> <text-field name="bay" v-model="product.bay" :attrs="{maxlength: 2}" format="uppercase"/> </cell> <cell :cols="1"> <text-field name="shelf" v-model.number="product.shelf" :attrs="{maxlength: 2}" format="integer"/> </cell> <cell :cols="2"> <text-field type="select" name="squashiness" v-model="product.squashiness" :options="['Bags','Bottles','Boxes','Sacks','Delicates','Prepacks','Split Cases']"/> </cell> </div> <div class="row"> <cell :cols="2"> <text-field name="identifier" v-model="product.identifier" /> </cell> <cell :cols="2"> <text-field name="grossWeight" after-class="input-group-addon" label="Gross Weight" v-model="product.grossWeight" format="numeric"><span slot="after">kg</span></text-field> </cell> <cell :cols="2"> <text-field name="substituteCode" v-model="product.substituteCode" /> </cell> <cell :cols="3"> <text-field name="outerCaseBarcode" v-model="product.outerCaseBarcode" format="integer"/> </cell> </div> <div class="row"> <cell :cols="12"> <text-field type="textarea" name="notes" v-model="product.notes" :attrs="{rows: 1}" /> </cell> </div> </div> <div class="row"> <cell :cols="12"> <button type="button" class="btn btn-sm" @click.prevent="returnToList">Cancel</button> <button type="button" class="btn btn-sm" @click.prevent="saveAndBack">Save, Back To List</button> <button type="button" class="btn btn-sm btn-primary" @click.prevent="save">Save and Continue</button> </cell> </div> </form> </tab-page> <tab-page page="Pricing"> <form class="edit-form"> <div class="form-fields"> <common-header :product="this.product" :error="this.error"></common-header> <div class="row"> <cell :cols="8"> <div class="row"> <cell :cols="2"> <text-field type="select" name="basedOn" v-model="product.basedOn" :options="['T','B','C']" :styles="{width:'100%'}"/> </cell> <cell :cols="2"><text-field name="priceBase" v-model.number="product.priceBase" format="currency"/></cell> <cell :cols="2"><text-field name="newPriceBase" v-model.number="product.newPriceBase" format="currency"/></cell> <cell :cols="2"> <text-field type="select" name="vatRating" v-model="product.vatRating" :options="[{ text: 'Zero', value: '0.00'},{text: 'Reduced', value: '5.00' },{text: 'Standard', value: '20.00'}]" @input="calcRRP"/> </cell> <cell :cols="2"><text-field name="price" label="Rainbow Price" v-model.number="product.price" format="currency" :attrs="{disabled:true}"/></cell> <cell :cols="2"><text-field name="unitPrice" label="Per unit/kg" v-model.number="product.unitPrice" format="currency" :attrs="{disabled:true}"/></cell> </div> </cell> </div> <div class="row"> <cell :cols="3"> <checkbox-field inline="true" name="hasRRP" label="Has RRP" v-model="product.hasRRP" @input="calcRRP"></checkbox-field> <checkbox-field v-if="product.hasRRP" inline="true" name="useNonFoodRRP" label="Non-food RRP" v-model="product.useNonFoodRRP" @input="calcRRP"></checkbox-field> </cell> <cell :cols="8"> <div class="row"> <template v-if="product.hasRRP"> <cell :cols="2"><text-field name="rrp" label="RRP" v-model.number="product.RRP" format="currency" :attrs="{disabled:true}"/></cell> <cell :cols="2" ><text-field name="manualRRP" label="Over-ride RRP" v-model.number="product.manualRRP" format="currency"/></cell> </template> <cell :cols="6"><text-field name="remark" label="Remark" v-model="product.remark" /></cell> <cell :cols="2"><button type="button" class="btn btn-sm btn-inline" @click.prevent="recalc">Recalculate Now</button></cell> </div> </cell> </div> </div> <button-bar></button-bar> </form> </tab-page> <tab-page page="History"> <form class="edit-form"> <div class="form-fields"> <common-header :product="this.product" :error="this.error"></common-header> <button-bar></button-bar> </div> </form> </tab-page> <tab-page page="Shop"> <form class="edit-form"> <div class="form-fields"> <common-header :product="this.product" :error="this.error"></common-header> <template v-if="this.product.shop==true"> <div class="row"> <cell :cols="6"> <button type="button" class="btn btn-sm btn-inline" @click.prevent="addShopLine">Add New</button> </cell> <cell :cols="6" :styles="{'text-align':'right'}"> <button type="button" class="btn btn-sm btn-inline" @click.prevent="autoLabel">Auto Label</button> </cell> </div> <div class="row"> <div class="col-xs-12"> <table id="shop-lines"> <thead> <tr> <th>Unit</th> <th class="price">Price</th> <th>Variety</th> <th class="barcode">Barcode</th> <th>Label</th> <th>&nbsp;</th> </tr> </thead> <tbody> <tr class="shop-line-row" v-for="(shopLine, index) in this.product.shopLines"> <td><text-field table-cell="true" :name="'unit'+index" type="select" v-model="shopLine.unit" :options="['2.5kg','1kg','500g','250g','125g','50g','25g','Unit (Low)','Unit (High)', 'Unit (Non-food)']" :styles="{width:'100%'}" /></td> <td class="price"><text-field table-cell="true" :name="'price'+index" v-model.number="shopLine.price" format="currency"/></td> <td><text-field table-cell="true" :name="'variety'+index" v-model="shopLine.variety"/></td> <td class="barcode"><text-field table-cell="true" :name="'barcode'+index" v-model.number="shopLine.barcode" format="integer"/></td> <td><text-field table-cell="true" :name="'label'+index" v-model="shopLine.label"/></td> <td><button @click.prevent="removeShopLine(index)">X</button></td> </tr> </tbody> </table> </div> </div> </template> <template v-else> <div class="row"> <cell :cols="12"> <p>This product is not sold at the shop</p> </cell> </div> </template> <button-bar></button-bar> </div> </form> </tab-page> </div> </div> </template> <script> import bus from '../../bus' import TabPage from '../TabPage' import TabLink from '../TabLink' import Cell from '../Cell' import TextField from '../TextField' import CheckboxField from '../CheckboxField' import CommonHeader from './CommonHeader' import ButtonBar from './ButtonBar' export default { data() { return { action:null, product: {}, productCopy:{}, page:'Product', error:"", errorField:null, validations:{ } } }, components:{ TabPage,TabLink,Cell,TextField,CheckboxField,CommonHeader,ButtonBar }, watch: { '$route' (to, from) { this.setAction(); } }, created () { bus.$on('SelectSupplier', (supplier) =>{ this.product.supplierCode=supplier.code; this.product.supplierName=supplier.name; }); bus.$on('SelectSubcategory', (subcategory)=> { this.product.subcategory=subcategory.name; this.product.subcategoryId=subcategory.id; this.product.category=subcategory.categoryName; this.product.categoryId=subcategory.categoryId; }); bus.$on("set-page", (page)=> { this.validatePage(); if (this.error == "") { var currentPage = this.page; this.page = page; bus.$emit("update-page", this.page); } }); bus.$on("button-action", (action)=> { this[action](); }); }, mounted(){ this.setAction(); if(this.action=="edit"){ this.buildTitle("Edit Product"); } else if(this.action=="dupe") { this.buildTitle("Duplicate Product"); } else if(this.action=="create") { this.buildTitle("Create Product"); } }, beforeRouteLeave (to, from, next) { if(_.isEqual(this.product, this.productCopy)){ next(); } else { var self=this; bootbox.confirm({ message: "Are you sure want to leave the product editor? You will lose any new or changed data", buttons: { confirm: { label: 'Back To List', }, cancel: { label: 'Continue Editing', } }, callback: function (result) { if(result){ next(); } else { next(false); } } }); } }, computed: { fullName () { return this.product.name + ", " + this.product.pack + this.product["size"]; }, displayName () { if (this.product.code && this.product.code.length == 5) { return this.product.code + ": " + this.fullName; } else { return this.fullName; } }, categorization (){ if (this.product.category && this.product.subcategory) { return this.product.category + ": " + this.product.subcategory; } else { return ""; } }, settings(){ return this.$store.state.settings; } }, methods: { //BUNCH OF METHODS REMOVED HERE TO BRING TEXT SIZE DOWN BELOW 30,000 } } </script> 

And here's the completely pared down TabPage component, whose inclusion in the above component causes compilation to hang:

<script> export default{ name:"tab-page", template:`<div>EMPTY</div>` } </script 

I have upgraded to the latest node (v6.9.4 LTS) but this didn't help.

5
  • Maybe: github.com/webpack/webpack-dev-server/issues/128 ? Commented Jan 30, 2017 at 17:51
  • I'm not using SASS at all. Not sure how/where to effect this UV_THREADPOOL_SIZE change mentioned. I tried process.env.UV_THREADPOOL_SIZE=128 in the dev-server.js script but the problem is still occurring. It's a massive show-stopper, as I simply cannot make any further progress if I can't use this component. Commented Jan 30, 2017 at 18:43
  • Did you notice you don't close the last </script> tag? Commented Jan 30, 2017 at 18:51
  • What do you mean? Looks like the script tags are fine in both components above. Am I missing something? Commented Jan 30, 2017 at 19:19
  • 1
    AAAARRGH!! I see what you mean now! I've started at that over and over without noticing. Commented Jan 30, 2017 at 19:36

1 Answer 1

2

Thankfully the problem turned out not to be anything troublingly obscure but the simple fact that I hadn't closed the script tag properly. I feel very stupid, but also relieved. Thanks for Roy J for pointing this out.

Sign up to request clarification or add additional context in comments.

2 Comments

I should add that even though this problem was a result of simple coding clumsiness on my part, I am a little surprised that webpack-dev-server, or whatever element in the tooling it is, wasn't able to spit out an error message alerting me to a syntax error in a specific file.
Same here I imported a module I didn't install (aws-sdk), no error just got stuck.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.