Skip to content
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

Integration with VueJS + Typescript possible ? #113

Open
lodacom opened this issue Sep 1, 2020 · 2 comments
Open

Integration with VueJS + Typescript possible ? #113

lodacom opened this issue Sep 1, 2020 · 2 comments

Comments

@lodacom
Copy link

lodacom commented Sep 1, 2020

I tried to integrate Ara Framework with Typescript and VueJs. My project comes with my own external library.
Here is my webpack config :

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const NodemonPlugin = require('nodemon-webpack-plugin');

const server = {
    target: 'node',
    entry: path.join(__dirname, 'src/server.js'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'fournisseur-app-server.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                options: {
                    presets: ['@babel/preset-env',{
                        'plugins': ['@babel/plugin-proposal-class-properties']}]
                }
            },
            {
                test: /\.tsx?$/,
                loader: 'ts-loader',
                exclude: /node_modules/,
                options: {
                    appendTsSuffixTo: [/\.vue$/],
                }
            },
            {
                test: /\.vue$/,
                exclude: /node_modules/,
                loader: 'vue-loader'
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'file-loader'
            },
            {
                test: /\.(eot|fsvg|ttf|otf|woff|woff2)$/,
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    publicPath: 'fonts'
                }
            },
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ]
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        new NodemonPlugin()
    ],
    resolve: {
        extensions: ['.ts', '.js', '.vue'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    }
}

const client = {
    target: 'web',
    node: {
        fs: 'empty',
        module: 'empty'
    },
    entry: path.join(__dirname, 'src/client.js'),
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'fournisseur-app-client.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                options: {
                    presets: ['@babel/preset-env',{
                        'plugins': ['@babel/plugin-proposal-class-properties']}]
                }
            },
            {
                test: /\.tsx?$/,
                loader: 'ts-loader',
                exclude: /node_modules/,
                options: {
                    appendTsSuffixTo: [/\.vue$/],
                }
            },
            {
                test: /\.vue$/,
                exclude: /node_modules/,
                loader: 'vue-loader'
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'file-loader'
            },
            {
                test: /\.(eot|fsvg|ttf|otf|woff|woff2)$/,
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    publicPath: 'fonts'
                }
            },
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ]
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin()
    ],
    resolve: {
        extensions: ['.ts', '.js', '.vue'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    }
};

module.exports = [server, client];

When I launch my Ara dev task ("ara:dev": "webpack --config araWebpack.config.js --watch --mode development"), it's crashed with this mysterious error :

webpack:///./node_modules/vue/dist/vue.esm.js?:9227
decoder = decoder || document.createElement('div');
^

ReferenceError: document is not defined
at decode (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:9227:26)
at cachedFn (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:163:33)
at Object.chars (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:9865:50)
at parseHTML (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:9388:17)
at parse (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:9731:3)
at baseCompile (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:11855:13)
at compile (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:11830:22)
at Function.compileToFunctions [as compile] (webpack:///./node_modules/←[4mvue←[24m/dist/vue.esm.js?:11713:20)

When I comment the server part in webpack config, client part is generated whithout any issue.

Here is my client.js :

import {Vue, renderVue} from 'hypernova-vue';

import Fournisseur from './components/Fournisseur';

import BootstrapVue from 'bootstrap-vue/dist/bootstrap-vue.esm';

import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css';

Vue.use(BootstrapVue);

document.addEventListener('NovaMount', (event) => {
    const { detail: { name } } = event
    switch (name) {
        case 'Fournisseur' :
            return renderVue(name, Vue.extend(Fournisseur));
    }
});

And here is my server.js :

import hypernova from 'hypernova/server';
import {renderVue, Vue} from 'hypernova-vue/server';
import express from 'express';
import path from 'path';

import BootstrapVue from 'bootstrap-vue/dist/bootstrap-vue.esm';

import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css';

import Fournisseur from './components/molecule/Fournisseur';

Vue.use(BootstrapVue);

hypernova({
    devMode: process.env.NODE_ENV !== 'production',
    getComponent(name) {
        switch (name) {
            case 'Fournisseur' :
                return renderVue(name, Vue.extend(Fournisseur));
        }
    },

    port: process.env.PORT || 3001,

    createApplication() {
        const app = express();

        app.use('/public', express.static(path.join(process.cwd(), 'dist')));

        return app;
    }
});

It's seem that the issue is coming from my external library. Like the latter was interpreted twice. I tried to exclude it, but without any effect.
Have you any idea to force this behaviour or to solve this kind of issue in Ara environnement ?

I specify that I didn't encounter this issue when I launch my server without Ara things.

@lodacom lodacom changed the title Integration with VueJS + Typescript Integration with VueJS + Typescript possible ? Sep 3, 2020
@marconi1992
Copy link
Member

Hi @lodacom, It seems a bootstrap-vue issue.

This error ReferenceError: document is not defined usually happen when we're using libraries requires the document reference. So it's not available in the node context. Do you know if the library is compatible with SSR?

Also, you can share the Fournisseur component code to try to reproduce it.

@lodacom
Copy link
Author

lodacom commented Sep 8, 2020

Hi @marconi1992, Thanks you for your reply.
I think my library is compatible with SSR. But I prefer to send you one of my component (the simplest ones) to judge by yourself :

import {Vue, Component, Prop, PropSync} from "vue-property-decorator";
import ButtonModel from "../../models/buttonModel"
import {CreateElement, VNode} from "vue";
import VueBis from 'vue';
import './Button.css';

const template = `
        <div>
    <div v-bind:class="_model.type+'Button '+_model.buttonColor+'Button' + ' container-align'" @click="action" v-bind:style="'width:'+ _model.width + ';height:' + _model.height + ';'">
        <div v-bind:class="_model.type+'LabelButton '+_model.labelColor+'LabelButton'" >
            {{ _model.buttonText }}
        </div>
    </div>
</div>
        `;

const compiledTemplate = VueBis.compile(template);

@Component
export default class Button extends Vue {
    @PropSync("model", {type: ButtonModel}) private _model!: ButtonModel;
    @Prop(Function) private action!: Function;

    constructor () {
        super();
    }

    render(createElement: CreateElement): VNode {
        return compiledTemplate.render.call(this, createElement);
    }
}

And here the model code :

export default class ButtonModel {
    private _buttonText!: string;
    private _labelColor: string;
    private _buttonColor: string;
    private _type: string;
    private _width: string;
    private _height: string;

    constructor(buttonText: string, width = "", height = "50px", labelColor = 'white', buttonColor = 'redBgRedBorder', type = 'default') {
        this._buttonText = buttonText;
        this._labelColor = labelColor;
        this._buttonColor = buttonColor;
        this._type = type;
        this._width = width;
        this._height = height;
    }

    get buttonText(): string {
        return this._buttonText;
    }

    set buttonText(value: string) {
        this._buttonText = value;
    }

    get labelColor(): string {
        return this._labelColor;
    }

    set labelColor(value: string) {
        this._labelColor = value;
    }

    get buttonColor(): string {
        return this._buttonColor;
    }

    set buttonColor(value: string) {
        this._buttonColor = value;
    }

    get type(): string {
        return this._type;
    }

    set type(value: string) {
        this._type = value;
    }

    get width(): string {
        return this._width;
    }

    set width(value: string) {
        this._width = value;
    }

    get height(): string {
        return this._height;
    }

    set height(value: string) {
        this._height = value;
    }
}

The Fournisseur component code is too complex to share here. But as I tested a smaller component and it makes the same error, I can share it. Here is the OffreFournisseur :

<template>
    <div>

        <br>
        <br>
        <br>
        <br>

        Produits du fournisseur

        <div><UgapButton :model="buttonContacter" :action="contacter"/></div>
        <br>
        <br>
        <br>
        <br>
        <br>

    </div>
</template>

<script lang="ts">
  import {Vue, Component, Prop} from "vue-property-decorator";
  import UgapButton from "@lodacom/vue-components/dist/js/components/atomes/Button/Button";


  import ButtonModel from "@lodacom/vue-components/dist/js/components/models/buttonModel";
  @Component({
      components: {
          UgapButton
      }
  })
  export default class OffreFournisseur extends Vue {
    @Prop(String) private ongletCourant!:string;
      private buttonContacter!: ButtonModel;

    constructor(){
      super();
        const model = new ButtonModel("Contacter", "151px", "45px");
        this.buttonContacter = model;
      this.$emit("routeChanged", this.ongletCourant);
    }

      contacter(){
          alert("boutton contacter");
      }

  }
</script>

<style scoped>

</style>

Then I replace the Fournisseur component by this one in client and server files. Then as I said I got the error.

Could you guide me and/or give me some advices to make my library compatible with SSR if not ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants