Skip to content

Added Vue3 support #746

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
May 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 30 additions & 31 deletions fixtures/vuejs-css-modules/App.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
<template>
<div id="app" class="red large justified lowercase block" :class="[$css.italic, $scss.bold, $less.underline, $stylus.rtl, $postcss.hidden]"></div>
<div class="red large justified lowercase block" :class="[$css.italic, $scss.bold, $less.underline, $stylus.rtl, $postcss.hidden]"></div>
</template>

<style module="$css">
.italic {
font-style: italic;
}
</style>

<style lang="scss" module="$scss">
.bold {
font-weight: bold;
}
</style>

<style lang="less" module="$less">
.underline {
text-decoration: underline;
}
</style>

<style lang="styl" module="$stylus">
.rtl
direction: rtl;
</style>

<style lang="postcss" module="$postcss">
.hidden {
visibility: hidden;
}
</style>

<style>
.red {
color: red;
Expand Down Expand Up @@ -30,33 +59,3 @@
display: block;
}
</style>


<style module="$css">
.italic {
font-style: italic;
}
</style>

<style lang="scss" module="$scss">
.bold {
font-weight: bold;
}
</style>

<style lang="less" module="$less">
.underline {
text-decoration: underline;
}
</style>

<style lang="styl" module="$stylus">
.rtl
direction: rtl;
</style>

<style lang="postcss" module="$postcss">
.hidden {
visibility: hidden;
}
</style>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The re-ordering works around a vue-loader bug - which was just merged :) vuejs/vue-loader#1671

4 changes: 4 additions & 0 deletions fixtures/vuejs-css-modules/main_v3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createApp } from 'vue';
import App from './App'

createApp(App).mount('#app');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vue2 code is pretty much compat with vue3, except for how you originally render the app. So I have v2 and v3 entry files.

File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions fixtures/vuejs/main_v3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createApp } from 'vue';
import App from './App'

createApp(App).mount('#app');
File renamed without changes.
File renamed without changes.
45 changes: 45 additions & 0 deletions fixtures/vuejs3-typescript/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<template>
<div id="app">
<img src="./assets/logo.png">
<hello></hello>
</div>
</template>

<script lang="ts">
import Hello from './components/Hello.vue'

class TestClassSyntax {

}

export default {
name: 'app',
components: {
Hello
}
}
</script>

<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

<style lang="scss">
#app {
display: flex;
color: #2c3e90;
}
</style>

<style lang="less">
#app {
margin-top: 40px;
}
</style>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typescript in vue2 vs vue3 is different enough that I have 2 separate directories.

Binary file added fixtures/vuejs3-typescript/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions fixtures/vuejs3-typescript/components/Hello.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
<li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
<br>
<li><a href="https://vuejs-templates.github.io/webpack/" target="_blank">Docs for This Template</a></li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li><a href="https://router.vuejs.org/" target="_blank">vue-router</a></li>
<li><a href="https://vuex.vuejs.org/" target="_blank">vuex</a></li>
<li><a href="https://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
</ul>
</div>
</template>

<script lang="ts">
export default {
name: 'hello',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}

ul {
list-style-type: none;
padding: 0;
}

li {
display: inline-block;
margin: 0 10px;
}

a {
color: #42b983;
}
</style>
4 changes: 4 additions & 0 deletions fixtures/vuejs3-typescript/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');
12 changes: 12 additions & 0 deletions fixtures/vuejs3-typescript/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es6",
"strict": true,
"module": "es2015",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
},
"include": [
"./**/*.ts"
]
}
15 changes: 14 additions & 1 deletion lib/WebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class WebpackConfig {
this.babelTypeScriptPresetOptions = {};
this.vueOptions = {
useJsx: false,
version: null,
};
this.eslintOptions = {
lintVue: false,
Expand Down Expand Up @@ -749,9 +750,21 @@ class WebpackConfig {
if (!(key in this.vueOptions)) {
throw new Error(`"${key}" is not a valid key for enableVueLoader(). Valid keys: ${Object.keys(this.vueOptions).join(', ')}.`);
}

if (key === 'version') {
const validVersions = [2, 3];
if (!validVersions.includes(vueOptions.version)) {
throw new Error(`"${vueOptions.version}" is not a valid value for the "version" option passed to enableVueLoader(). Valid versions are: ${validVersions.join(', ')}.`);
}
}

this.vueOptions[key] = vueOptions[key];
}

this.vueOptions = vueOptions;
// useJsx and vue 3 are not currently supported by Encore
if (this.vueOptions.useJsx && this.vueOptions.version === 3) {
throw new Error('Setting both "useJsx: true" and "version: 3" for enableVueLoader() is not currently supported. Please use version: 2 or disable useJsx.');
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that the babel preset that enables this doesn't work yet - vuejs/jsx-vue2#106

}

enableEslintLoader(eslintLoaderOptionsOrCallback = () => {}, eslintOptions = {}) {
Expand Down
6 changes: 5 additions & 1 deletion lib/config-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const PluginPriorities = require('./plugins/plugin-priorities');
const applyOptionsCallback = require('./utils/apply-options-callback');
const sharedEntryTmpName = require('./utils/sharedEntryTmpName');
const copyEntryTmpName = require('./utils/copyEntryTmpName');
const getVueVersion = require('./utils/get-vue-version');
const tmp = require('tmp');
const fs = require('fs');
const path = require('path');
Expand Down Expand Up @@ -101,7 +102,10 @@ class ConfigGenerator {
};

if (this.webpackConfig.useVueLoader) {
config.resolve.alias['vue$'] = 'vue/dist/vue.esm.js';
const vueVersion = getVueVersion(this.webpackConfig);
if (vueVersion === 2) {
config.resolve.alias['vue$'] = 'vue/dist/vue.esm.js';
}
}

if (this.webpackConfig.usePreact && this.webpackConfig.preactOptions.preactCompat) {
Expand Down
17 changes: 14 additions & 3 deletions lib/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,28 @@ const features = {
],
description: 'process TypeScript files with Babel'
},
vue: {
vue2: {
method: 'enableVueLoader()',
// vue is needed so the end-user can do things
// vue-template-compiler is a peer dep of vue-loader
packages: [
{ name: 'vue' },
{ name: 'vue-loader', enforce_version: true },
{ name: 'vue', version: '^2.5' },
{ name: 'vue-loader', version: '^15' },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New feature to force what version to show when we recommend something to the user. Causes yarn add vue@^2 to be output.

{ name: 'vue-template-compiler' }
],
description: 'load Vue files'
},
vue3: {
method: 'enableVueLoader()',
// vue is needed so the end-user can do things
// @vue/compiler-sfc is an optional peer dep of vue-loader
packages: [
{ name: 'vue', enforce_version: true },
{ name: 'vue-loader', enforce_version: true },
{ name: '@vue/compiler-sfc' }
],
description: 'load Vue files'
},
'vue-jsx': {
method: 'enableVueLoader()',
packages: [
Expand Down
30 changes: 25 additions & 5 deletions lib/friendly-errors/transformers/missing-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

'use strict';

const getVueVersion = require('../../utils/get-vue-version');

const TYPE = 'loader-not-enabled';

function isMissingLoaderError(e) {
Expand All @@ -24,14 +26,25 @@ function isMissingLoaderError(e) {
}

function isErrorFromVueLoader(filename) {
return filename.includes('??vue-loader-options');
// vue2
if (filename.includes('??vue-loader-options')) {
return true;
}

// vue3
if (filename.includes('vue-loader/dist??')) {
return true;
}

return false;
}

function getFileExtension(filename) {
// ??vue-loader-options
if (isErrorFromVueLoader(filename)) {
// vue is strange, the "filename" is reported as something like
// /path/to/project/node_modules/vue-loader/lib??vue-loader-options!./vuejs/App.vue?vue&type=style&index=1&lang=scss
// vue2: /path/to/project/node_modules/vue-loader/lib??vue-loader-options!./vuejs/App.vue?vue&type=style&index=1&lang=scss
// vue3: /path/to/project/node_modules/vue-loader/dist??ref--4-0!./vuejs/App.vue?vue&type=style&index=1&lang=scss
const langPos = filename.indexOf('lang=') + 5;
let endLangPos = filename.indexOf('&', langPos);
if (endLangPos === -1) {
Expand All @@ -47,7 +60,7 @@ function getFileExtension(filename) {
return split.pop();
}

function transform(error) {
function transform(error, webpackConfig) {
if (!isMissingLoaderError(error)) {
return error;
}
Expand All @@ -68,7 +81,7 @@ function transform(error) {
error.loaderName = 'react';
break;
case 'vue':
error.loaderName = 'vue';
error.loaderName = 'vue' + getVueVersion(webpackConfig);
break;
case 'tsx':
case 'ts':
Expand All @@ -86,4 +99,11 @@ function transform(error) {
return error;
}

module.exports = transform;
/*
* Returns a factory to get the function.
*/
module.exports = function(webpackConfig) {
return function(error) {
return transform(error, webpackConfig);
};
};
4 changes: 3 additions & 1 deletion lib/loaders/vue.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
const WebpackConfig = require('../WebpackConfig'); //eslint-disable-line no-unused-vars
const loaderFeatures = require('../features');
const applyOptionsCallback = require('../utils/apply-options-callback');
const getVueVersion = require('../utils/get-vue-version');

module.exports = {
/**
* @param {WebpackConfig} webpackConfig
* @return {Array} of loaders to use for Vue files
*/
getLoaders(webpackConfig) {
loaderFeatures.ensurePackagesExistAndAreCorrectVersion('vue');
const vueVersion = getVueVersion(webpackConfig);
loaderFeatures.ensurePackagesExistAndAreCorrectVersion('vue' + vueVersion);

const options = {};

Expand Down
Loading