0

I have a typescript + vue + webpack application and I want separate html from code.
I have follow this tutorial and I have made a simple Hello Word.

Webpack config

const path = require('path');

module.exports = {
    mode: "development",
    entry: './src/app.ts',
    output: {
        path: path.resolve('dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.(ts|tsx)?$/,
                loader: 'ts-loader',
                exclude: /node_modules/                
            },
            {
                test: /.html$/,
                loader: "vue-template-loader",
                exclude: /index.html/
            }
        ]
    },
    resolve: {
        extensions: [
            '.js',
            '.vue',
            '.tsx',
            '.ts'
        ]
    }
};

Html

<div>
    <h2>Hello from {{message}}</h2>
</div>

Vue Component

import Vue from "vue";
import Component from "vue-class-component";
// template: '<button @click="onClick">Click!</button>'
import WithRender from "./home.html";

@WithRender
@Component
export default class HomeComponent extends Vue {

    public message: string = "Word";

    constructor() {
        super();
    }

    mounted() { }
}

After I have added this shim

declare module '*.html' {

        import Vue, { ComponentOptions, FunctionalComponentOptions } from 'vue'
        interface WithRender {
            <V extends Vue, U extends ComponentOptions<V> | FunctionalComponentOptions>(options: U): U
            <V extends typeof Vue>(component: V): V
        }

        const withRender: WithRender
        export default withRender
}

I have (almost) understand how typescript decorators work but I don't understand the shim code, how it is possible that this code inject the html into the Vue component ?

I have readed about Decorators from Typescript site

2 Answers 2

1

vue-template-loader compiles the HTML template into a render function, which @WithRender inserts into the class definition.

For instance, this HTML:

<div>Hello world</div>

is converted into this render function:

render(h) {
  return h('div', 'Hello world')
}

Then, applying @WithRender (the result of importing the example HTML template above) to class Foo extends Vue {} results in:

class Foo extends Vue {
  render(h) {
    return h('div', 'Hello world')
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Try something like this.

src/view/FirstView.ts

import "ts-polyfill";
import {defineComponent} from "vue";
import {route} from "@product/router/Routes";

const component = defineComponent({
    name: 'FirstView',
    components: {},
    template: require("@product/template/FirstView.html"),
    data() {
        return {
            message: 'FirstView',
            route
        };
    }
})
export default component

src/template/FirstView.html

<div class="flex space-between">
    <h1>{{ message }}</h1>
    <router-link :to="{ name: route.second }">To second</router-link>
</div>

Webpack config

const path = require('path');
const webpack = require('webpack');

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
        entry: {
            'product': './src/App.ts',
        },
        output: {
            path: path.resolve(__dirname, 'public/'),
            publicPath: '/',
            filename: 'js/[name].js'
        },
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    loader: 'ts-loader',
                    options: {
                        appendTsSuffixTo: [/\.vue$/],
                        configFile: 'tsconfig.json',
                        allowTsInNodeModules: true
                    }
                },
                {
                    test: /\.jsx?$/,
                    type: 'javascript/esm',
                    use: {
                        loader: 'babel-loader',
                    },
                    exclude: /node_modules/
                },
                {
                    test: /\.html$/,
                    use: ['html-loader']
                }
            ]
        },
        plugins: [],
        resolve: {
            plugins: [new TsconfigPathsPlugin({configFile: "tsconfig.json"})],
            alias: {
                'vue$': 'vue/dist/vue.esm-bundler.js',
            },
            extensions: ['*', '.ts', '.js', '.json']
        }
};

tsconfig.json

module.exports = {
    "runtimeCompiler": true,
    "compilerOptions": {
        "rootDirs": [
            "src/"
        ],
        "paths": {
            "@product/*": ["src/*"]
        },
    },
    "include": [
        "src/**/*.ts"
    ]
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.