Vue-TypeScript-SFC-未定义属性或方法

时间:2019-10-08 07:00:35

标签: typescript vue.js

尝试使用VueTypeScript构建单个文件组件。我经常遇到错误。

[Vue warn]: Property or method "foo" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property

FooBar.vue

<template lang="pug">
    section.section
        span {{ foo }}
</template>
<script lang="ts">
    import Vue from 'vue'

    interface State {
        foo: string
    }

    export default Vue.extend({
        data(): State {
            return {
                foo: '',
            }
        },
        mounted() {
            this.foo = "Bar";
        }
    })
</script>

现在,如果删除lang="ts"属性和State接口,则可以正常工作。在这里茫然。这是应用程序的其余部分。忽略我刚刚尝试过的混乱工作。

tsconfig.json

{
    "compileOnSave": true,
    "compilerOptions": {
        "strict": true,
        "moduleResolution": "node",
        "target": "es6",
        "noImplicitAny": true,
        "noImplicitThis": true,
        "noImplicitReturns": true,
        "sourceMap": true,
        "baseUrl": ".",
        "paths": {
            "~/*": [
                "./*"
            ],
            "@/*": [
                "./*"
            ]
        }
    },
    "include": [
        "./components/*.ts",
        "./components/*.vue",
        "./components/**/*.ts",
        "./components/**/*.vue"
    ],
    "files": [
        "./src/vue-shims.d.ts"
    ],
    "exclude": [
        "node_modules"
    ]
}

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const AssetsPlugin = require('assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = function (env = {}) {
    if (env.production) {
        process.env.NODE_ENV = 'production';
    }

    function makeStyleLoader(type) {
        const cssLoader = {
            loader: 'css-loader',
            options: {
                minimize: env.production
            }
        };

        const loaders = [cssLoader];

        if (type) {
            loaders.push(type + '-loader');
        }
        if (env.production) {
            return ExtractTextPlugin.extract({
                use: loaders,
                fallback: 'vue-style-loader'
            });
        } else {
            return ['vue-style-loader'].concat(loaders);
        }
    }

    // Determine plugins per environment
    let plugins;

    if (env.production) {
        plugins = [
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: '"production"'
                }
            }),
            new webpack.optimize.UglifyJsPlugin({
                compress: {
                    warnings: false
                }
            }),
            new ExtractTextPlugin({
                filename: 'css/style.min.css?[contenthash]'
            }),
            new AssetsPlugin({
                filename: 'assets.json',
                path: path.resolve(__dirname, '../public/assets'),
                fullPath: false
            })
        ];
    } else if (env.standalone) {
        plugins = [
            new webpack.HotModuleReplacementPlugin(),
            new HtmlWebpackPlugin({
                hash: true,
                template: './src/index.html',
                filename: './index.html' //relative to root of the application
            })
        ];
    } else {
        plugins = [
            new webpack.HotModuleReplacementPlugin()
        ];
    }

    return {
        entry: './main.js',
        output: {
            path: path.resolve(__dirname, '../vue/public'),
            publicPath: env.production ? '/public/' : 'http://localhost:8080/',
            filename: env.production ? 'js/main.min.js?[chunkhash]' : 'js/main.js'
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    loader: 'vue-loader',
                    options: {
                        loaders: {
                            pub: 'pug-loader',
                            css: makeStyleLoader(),
                            less: makeStyleLoader('less'),
                            ts: 'ts-loader'
                        }
                    }
                },
                {
                    test: /\.pug$/,
                    exclude: /node_modules/,
                    loader: 'pug-loader',
                },
                {
                    test: /\.tsx?$/,
                    loader: 'ts-loader',
                    exclude: /node_modules/,
                    options: {
                        appendTsSuffixTo: [/\.vue$/],
                    }
                },
                {
                    test: /\.js$/,
                    loader: 'babel-loader',
                    exclude: /node_modules/
                },
                {
                    test: /\.css$/,
                    use: makeStyleLoader()
                },
                {
                    test: /\.less$/,
                    use: makeStyleLoader('less')
                },
                {
                    test: /\.(png|jpg|svg)$/,
                    loader: 'url-loader'
                }
            ]
        },
        plugins: plugins,
        resolve: {
            extensions: ['.ts', '.js', '.vue', '.json'],
            alias: {
                'vue$': 'vue/dist/vue.esm.js',
                Components: path.resolve(__dirname, 'components/'),
                Store: path.resolve(__dirname, 'store/'),
                Src: path.resolve(__dirname, 'src/'),
                Assets: path.resolve(__dirname, 'assets/')
            }
        },
        performance: {
            hints: false
        },
        devServer: {
            historyApiFallback: true,
            disableHostCheck: true,
            noInfo: true,
            quiet: true,
            clientLogLevel: 'silent',
            contentBase: false,
            hot: true,
            headers: {
                'Access-Control-Allow-Origin': '*'
            }
        },
        devtool: env.production ? false : '#cheap-module-eval-source-map'
    };
};

main.js

import Vue from 'vue';
import VueRouter from 'vue-router';
import Vuex from "vuex";

import App from './components/App';
import FooBar from './components/FooBar';

Vue.use(VueRouter);

const router = new VueRouter({
    routes: [
        { path: '/', component: FooBar }
    ],
    mode: 'history'
});

Vue.use(Vuex);

import application from './store/Application';

const store = new Vuex.Store({
    modules: {
        application
    }
});

const app = new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app');

package.json

{
"name": "foo-bar-demo",
"description": "Demo",
"version": "0.1.0",
"author": "John Doe",
"scripts": {
    "dev": "node clean.js && webpack-dev-server",
    "standalone": "node clean.js && webpack-dev-server --env.standalone",
    "build": "webpack --env.production"
},
"browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
],
"dependencies": {
    "axios": "^0.19.0",
    "bulma": "^0.7.5",
    "vue": "^2.5.13",
    "vue-resource": "^1.3.5",
    "vue-router": "^3.1.3",
    "vuex": "^3.1.1"
},
"devDependencies": {
    "assets-webpack-plugin": "^3.5.1",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "eslint-config-prettier": "^4.1.0",
    "eslint-plugin-prettier": "^3.0.1",
    "extract-text-webpack-plugin": "^3.0.2",
    "file-loader": "^1.1.4",
    "html-webpack-plugin": "^3.2.0",
    "jest": "^24.1.0",
    "less": "^2.7.3",
    "less-loader": "^4.0.5",
    "prettier": "^1.16.4",
    "pug": "^2.0.4",
    "pug-loader": "^2.4.0",
    "ts-loader": "^6.2.0",
    "typescript": "^3.6.3",
    "vue-class-component": "^7.1.0",
    "vue-jest": "^4.0.0-0",
    "vue-loader": "^14.2.2",
    "vue-property-decorator": "^8.2.2",
    "vue-template-compiler": "^2.6.10",
    "webpack": "^4.41.0",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.2"
}
}

2 个答案:

答案 0 :(得分:1)

如果要使用打字稿,则必须使用npm或yarn安装它,因为默认情况下vue使用javascript。

通过此链接输入打字稿: https://www.npmjs.com/package/typescript

因此,当您删除lang=ts时,它会将脚本读取为javascript。

答案 1 :(得分:0)

三天后解决。我必须将ts-loader包含在webpack.config.js中的vue规则中

ts: [
    {
        loader: 'ts-loader',
        options: {
            appendTsSuffixTo: [/\.vue$/]
        }
    }
]