开发者问题收集

Typescript Vue基于类的组件投掷错误无法设置Laravel Mix中未定义的属性“渲染”

2020-05-20
1961

我正在使用 Laravel Mix 编译我的 Vue 组件,为此,我使用了 TypeScript 和基于类的组件。每个单独的类都从组件中导出,并且主应用程序脚本中的上下文需要每个单独的组件,但在渲染 Vue 期间抛出错误。

Uncaught TypeError: Cannot set property 'render' of undefined
    at normalizeComponent (componentNormalizer.js:24)

我搜索了整个互联网,但人们只谈论无效的导出类。我确定组件中的导出类是有效的。我不知道我做错了什么。

当我回到纯 JavaScript 中的基于对象的组件时,一切都很完美,所以可能是 TypeScript 配置错误或其他问题。我彻底放弃了:(

app.ts

import Vue from 'vue';
import _ from "lodash"

export default class App {

    protected registerComponents(): void {
        const components = require.context('./', true, /\.vue$/i);

        components.keys().forEach((componentPath) => {
            // @ts-ignore
            const componentName = componentPath
                .split('/').pop() // full component name
                .split('.').slice(0, 1).shift(); // component name without extension

            Vue.component(
                _.kebabCase(componentName),
                components(componentPath)
            );
        })
    }

    protected boot(): void {
        this.registerComponents();
    }

    public init(): Vue {
        this.boot();

        return new Vue({
            el: '#main',
        });
    }
}

EventSignUpForm.vue

<template>
    <div>
        <p>Long-form v-model example</p>
    </div>
</template>

<script lang="ts">
    import Vue from 'vue'
    import {Component} from 'vue-property-decorator';

    @Component({
        name: 'EventSignUpForm',
    })
    export class EventSignUpForm extends Vue {

        protected count = 0

        public increment() {
            this.count++
        }

        public decrement() {
            this.count--
        }
    }

    export default EventSignUpForm;
</script>

tsconfig.json

{
    "compilerOptions": {
        "target": "es5",
        "module": "es2015",
        "moduleResolution": "node",
        "strict": true,
        "jsx": "preserve",
        "importHelpers": true,
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "sourceMap": true,
        "baseUrl": ".",
        "types": [
            "node",
            "webpack-env"
        ],
        "paths": {
            "@/*": ["./resources/js/*"]
        },
        "lib": [
            "esnext",
            "dom",
            "dom.iterable",
            "scripthost"
        ]
    },
    "include": [
        "resources/js/**/*.ts",
        "resources/js/**/*.tsx",
        "resources/js/**/*.vue"
    ],
    "exclude": [
        "node_modules"
    ]
}

webpack.mix.js

class WebpackMix {
    constructor() {
        this.mix = require('laravel-mix');
    }

    configureWebpack(){
        this.mix.webpackConfig({
            module: {
                rules: [
                    {
                        test: /\.tsx?$/,
                        loader: "ts-loader",
                        exclude: /node_modules/,
                    }
                ]
            },
            resolve: {
                extensions: ["*", ".js", ".jsx", ".vue", ".ts", ".tsx"],
                alias: {
                    '@': path.resolve(__dirname, 'resources', 'js'),
                },
            }
        });
    }
    // others things  
}
2个回答

EventSignUpForm.vue : 将组件 export 设为 export default

export class EventSignUpForm extends Vue 

更改为

export default class EventSignUpForm extends Vue

并从底部删除

export default EventSignUpForm;
Szymon Szymkowiak
2020-05-20

我的同事帮我解决了这个相当棘手的问题。

我们所做的是将 webpack.mix.js 添加到 ts-loader 选项对象中。我们需要将 TS 后缀附加到 Vue 组件。现在是:

rules: [
  {
    test: /\.tsx?$/,
    loader: 'ts-loader',
    exclude: /node_modules/,
    options: {
      appendTsSuffixTo: [/\.vue$/]
    }
  }
]

我们接下来要做的是将 tsconfig.js compilerOptions.module 更改为 commonjs 而不是 es2015 ,如下所示:

{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        // the rest remain unchanged
    }
}

最后一件事是所有 imports/require Vue 组件必须是默认导入,我只在 require.context 中使用了 import,但必​​须更改为:

protected registerComponents(): void {
  const components = require.context('./', true, /\.vue$/i);

  components.keys().forEach((componentPath) => {
    // @ts-ignore
    const componentName = componentPath
      .split('/').pop() // full component name
      .split('.').slice(0, 1).shift(); // component name without extension

    Vue.component(
      _.kebabCase(componentName),
      components(componentPath).default
    );
  })
}

这解决了我的问题,感谢 Adrian 抽出时间并给出可行的解决方案 :)

plumthedev
2020-05-24