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.
.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
All of the components should be displayed.
In my example code, I expect A B C D
to be displayed in the UI.
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.
I use multiple components to build my UI, so only some of the UI is displayed right now.
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.
| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | 1.8.1
| Node | 8.11.1
| npm/Yarn | 5.6.0
| Operating System | Windows 10
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
Most helpful comment
@oksurf add the following to your package.json: