Reputation: 7080
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
Upvotes: 0
Views: 941
Reputation: 29
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"
]
}
Upvotes: 0
Reputation: 138226
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')
}
}
Upvotes: 1