Parcel: Cannot have multiple Vue components in template

Created on 13 May 2018  路  24Comments  路  Source: parcel-bundler/parcel

馃悰 bug report

When I use multiple Vue components in my Vue template, only the first child component of a parent component appears to be displayed after minification. This happens when building the code for production, and does not happen when building for development or when using the --no-minify parameter.

馃帥 Configuration (.babelrc, package.json, cli command)

.babelrc: N/A

package.json:

{
  "name": "testapp",
  "version": "1.0.0",
  "description": "testapp",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "parcel build src/index.html",
    "dev": "parcel src/index.html"
  },
  "author": "Steffen",
  "license": "ISC",
  "dependencies": {
    "vue": "^2.5.16"
  },
  "devDependencies": {
    "@vue/component-compiler-utils": "^1.2.1",
    "vue-template-compiler": "^2.5.16"
  }
}

cli command:

parcel build src/index.html

馃 Expected Behavior

All of the components should be displayed.

In my example code, I expect A B C D to be displayed in the UI.

馃槸 Current Behavior

Only the first child component of a parent component appears to be displayed.

In my example code, A B is displayed in the UI. This means that component A did not display component B and C, and the App component did not display component D.

馃拋 Possible Solution

馃敠 Context

I use multiple components to build my UI, so only some of the UI is displayed right now.

馃捇 Code Sample

Please see the example code here:

https://github.com/SteffenL/parcel-vue-bug-repro/tree/vue-components

Here is a smaller example template:

<template>
<div id="app">
    <A /> <!-- displayed -->
    <B /> <!-- not displayed -->
</div>
</template>

<script>
import A from './A.vue';
import B from './B.vue';

export default {
    components: {
        A,
        B
    }
};
</script>

Building the code:

npm install
npm run build

Serve the files located in the dist/ directory.

馃實 Your Environment

| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | 1.8.1
| Node | 8.11.1
| npm/Yarn | 5.6.0
| Operating System | Windows 10

Bug

Most helpful comment

@oksurf add the following to your package.json:

"posthtml": {
  "recognizeSelfClosing": true
}

All 24 comments

FYI, this .uglifyrc config is not helping:

{
    compress: false,
    mangle: false
}

In VueAsset#compileTemplate, I have found that the value of html.value is unexpected.

Let's say that the original template is the following:

<span>A
    <ComponentB />
    <ComponentC />
</span>

At some point, that turns into the following:

<span>A <ComponentB> <ComponentC> </ComponentC></ComponentB></span>

This then goes through the Vue template compiler.

I was able to work around the problem like so:

<span>A
    <ComponentB></ComponentB>
    <ComponentC></ComponentC>
</span>

Something is doing the wrong thing here.

I'm working on the project with full-featured vue, and that's working good.
Could you, please, make a minimal reproducing repo?

@houd1ni I listed one before:

https://github.com/SteffenL/parcel-vue-bug-repro/tree/vue-components

Did you try this?

@SteffenL nope. Haven't noticed. Will do :+1:

@SteffenL

Good news: your problem is connected with mine one https://github.com/parcel-bundler/parcel/issues/1294

You may install the bundler locally, like I do with every project, then change that lines of code (see last messages there). You'll have good minified vue project :smile:

Then wait until the maintainers apply the fixes.

@houd1ni Thanks for letting me know!

@DeMoorJasper I have investigated further and found that the problem is with posthtml and its lack of support for self-closing custom tags.

const posthtml = require('posthtml');

const html = `
<span>A
    <ComponentB />
    <ComponentC />
</span>
`;

const result = posthtml()
  .process(html, { sync: true })
  .html;

console.log(result);

This code turns the template into the following:

<span>A
    <ComponentB>
    <ComponentC>
</ComponentC></ComponentB></span>

There is an open issue for this:
https://github.com/posthtml/posthtml/issues/221

Based on comments, I added xmlMode: true:

const posthtml = require('posthtml');

const html = `
<span>A
    <ComponentB />
    <ComponentC />
</span>
`;

const result = posthtml()
  .process(html, {
    sync: true,
    xmlMode: true
  }).html;

console.log(result);

This results in the following template:

<span>A
    <ComponentB></ComponentB>
    <ComponentC></ComponentC>
</span>

This does not seem ideal to me, and it would be a breaking change that would require users to write templates with XML syntax.

Example:

<span>A
    <img>
    <ComponentB />
    <ComponentC />
</span>

Turns into:

<span>A
    <img></span>

Code for reproducing the problem with posthtml:
https://github.com/SteffenL/parcel-vue-bug-repro/tree/posthtml

Run it with node src/index.js.

This has been reported before: #1103
Related PR: #1316

Passing the recognizeSelfClosing: true option to posthtml fixed self-closing tags for me in dev mode. And this option doesn't force html tags like , , to close.

But there is another html compressing pass (htmlnano) that I don't know how to fix, thus I skipped it for my project.

What if we change

if (descriptor.template) {
      parts.push({
        type: descriptor.template.lang || 'html',
        value: descriptor.template.content.trim()
      });
    }

Into this:

if (descriptor.template) {
      parts.push({
        type: descriptor.template.lang || 'html',
        value: descriptor.template.content.trim(),
        final: true
      });
    }

Inside vueasset.js than it should skip all the processing after vueasset.js for html

Sent with GitHawk

@DeMoorJasper

Just checked. It works in the case of usual vue tempalts, but draws nothing in the case of pug. <template lang="pug"> I've previously installed pug.

@houd1ni Ow yeah the final flag would tell parcel to not transpile pug, hmm that sucks. Not sure how to fix this anymore.

@DeMoorJasper

It's interesting that by idea (and it's realised for webpack by vue-loader), template language should be transpiled to vue-template (that is valid xml) and then to JS-render-functions, that I've mentioned earlier.

So, I guess, that VueAssets could transpile template, if some lang attribute is presented, to xml(html), then feed it to vue-template itself, huh?

Still seeing the same problem with the latest code.

Changing:
<span>A <ComponentB /> <ComponentC /> </span>
to:
<span>A <ComponentB></ComponentB> <ComponentC></ComponentC> </span>
seems to work but wish they would fix this...

@oksurf add the following to your package.json:

"posthtml": {
  "recognizeSelfClosing": true
}

Thanks @evanleck. That works for me.

Another possibility is to add a .posthtmlrc file to the root of your project with this content:

{
  "recognizeSelfClosing": true
}

Thanks @evanleck. That works for me.

Another possibility is to add a .posthtmlrc file to the root of your project with this content:

{
  "recognizeSelfClosing": true
}

Are there any caveats settings this somehow as a default for vue projects?

Are there any caveats settings this somehow as a default for vue projects?

(Here are the docs for that option: https://github.com/fb55/htmlparser2/wiki/Parser-options#option-recognizeselfclosing - posthtml-parser uses htmlparser2 under the hood)

Right now I have self-closing disabled in eslint to avoid this, but it will be nite to have this in parcel 2.x

The issue title is a bit misleading. In my experience self-closing tags don't work for html tags as well as vue components, so it's not specific to just using multiple vue components

"posthtml": {
  "recognizeSelfClosing": true
}

This isn't working for me. Do I need to do anything else than adding it to package.json?

Just wasted half a day on this. So infuriating.

Pretty sure this has been fixed in Parcel 2 as we no longer run it through posthtml

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jsftw86 picture jsftw86  路  3Comments

dsky1990 picture dsky1990  路  3Comments

medhatdawoud picture medhatdawoud  路  3Comments

philipodev picture philipodev  路  3Comments

jzimmek picture jzimmek  路  3Comments