Compiled Vue file source cannot be required via the ES6 module system. It causes a strict mode error to be thrown.
My team is developing an interface module. The goal is to consolidate our Vue components across several projects. The vue components are defined as '.vue' files. We precompile these files so they can be easily exported from our interface module as plain javascript. The strict mode fun arrises when we then go to require our interface module in our application code. Our applications use ES6 style imports. Because the render function created by 'vue-template-compiler' contains the 'with' keyword, the library cannot be required.
This seems to be a decent barrer to developing Vue UI kit modules. Any precompiled vue files cannot be imported via ES6 imports.
I'll see if I can update the code gen to work without the 'with' statement. If I'm successful and happy with the quality I'll create a PR.
@RobertWHurst thanks, that might prove difficult. It would require a decent rewrite of the current compiler implementation.
That said, what module system / bundler are you using for your application? I assume Webpack? Is there any reason you are not directly importing vue
files? Above all else, in Webpack you can use the plain require
syntax to avoid forcing the component module into strict mode.
@yyx990803 I understand, I have some experience working on codegen. I know it's a lot of work, but it might be worth while for both of us should my solution work for you. I'll aim to follow your coding standards as much as possible and avoid performance penalties. Removing with should be a good start as I believe V8 always de-optimizes code inside a with statement because it cannot track the sources of the variables within the with block.
We're using webpack at the moment. We want to avoid exporting vue files because our UI will be shared with 3rd parties. We want to be able to share components as easily as possible. We also wrap the compiled vue templates with UMD wrappers using babel. With this the idea was to allow 3rd parties without a build system to simply add the components they need via script tags or import statements provided vue is on the page.
@RobertWHurst yes, it would definitely be great if we can get rid of with
, and I appreciate your willingness to work on it! So let me outline some reasons for not doing it in the first place:
The use of with
is primarily because it gets rid of the need for parsing and scope analysis of the JavaScript expressions embedded inside templates, thus greatly reducing the size and complexity of the codegen itself. Since the template compiler is included in the standalone build that runs in the browser, payload size is still an important concern.
We can, of course, achieve the removal of with
if we employ proper AST analysis of the expressions, but that would entail a full sized JavaScript parser which would bloat the compiler size significantly.
One option is we would ship the current compiler (using with
) in the standalone build, and use a separate compiler in build tools. However this would result in two parallel compiler implementations and greatly increase maintenance cost and surface for potential bugs.
A probably better option would be to create a post-compiler for already-generated render function code. Essentially, an optional phase that turns code that contains with
into code that doesn't (by rewriting identifiers). This makes it decoupled from the "base" compiler so we can use it during build phases without worrying about size. It could also be turned off to improve compilation performance when with
is not a concern.
Implementation wise, this could technically be achieved via a Babel plugin, but I'm open to alternatives that you are more familiar with. But ideally, this can be a standalone npm package since it's purely code transform and has no hard coupling with Vue source code.
doing some digging on working around this while I'm currently seeing this problem while looking at an issue vuejs/vue-loader#438 ... but so far no luck.
Situation:
require()
, no import
'umd'
Yet still 'use strict'
is added to the bundled code. No idea why.
@LinusBorg Strange. Looking forward the the possibility of clearing this whole class of error.
@yyx990803 Sounds good. Going to try the babel plugin approach first. Back soon 馃嵒
I made a quick test to see if there are perf implications and that's the result https://albertxing.com/stool/#839ed9e58082751d2ad0be7e98652e28 I would like to have at least the option to decide whether to run my vue code in strict mode or not
@yyx990803 the vue-templae-compiler package uses strict mode:
https://github.com/vuejs/vue/blob/dev/packages/vue-template-compiler/build.js#L1
Could that lead to exports of precompiled components be in strict mode? As desribed above, I experience this even with a webpack1+require()-only build setup.
Edit:
_Disclaimer: So far, this is mostly just guessing on my part._
I Would suspect that this can create problems with the template-compiler? could we disable strict mode for rollup?
Made a bit of progress last light. I'll post a demo in the next few days. Decided to go for a standalone module for now. The idea being that it can be used alone or wrapped in a module for use with babel/webpack/browserify/etc.
@RobertWHurst I happened to realize that it could be done more efficiently by hacking Buble. And since I was already using a custom build of Buble in vue-template-es2015-compiler, I was able to implement with
removal in it today.
vue-template-es2015-compiler
is a dependency of vue-loader
, so if you do a fresh install of vue-loader
now, you should get render functions without with
by default.
Still, thanks for your interest in contributing to this!
@yyx990803 Ah, very cool. Cheers 馃嵒
Very amazing work!
Most helpful comment
@RobertWHurst I happened to realize that it could be done more efficiently by hacking Buble. And since I was already using a custom build of Buble in vue-template-es2015-compiler, I was able to implement
with
removal in it today.vue-template-es2015-compiler
is a dependency ofvue-loader
, so if you do a fresh install ofvue-loader
now, you should get render functions withoutwith
by default.Still, thanks for your interest in contributing to this!