基于 Typescript Vue class 的组件抛出错误 Cannot set 属性 'render' of undefined in Laravel mix
Typescript Vue class-based components throwing error Cannot set property 'render' of undefined in Laravel mix
我正在使用 Laravel Mix 来编译我的 Vue 组件,为此,我使用了 TypeScript 和基于 class 的组件。每个单独的 class 都是从组件中导出的,并且主应用程序脚本中的上下文需要每个单独的组件,但是在呈现 Vue 时抛出错误。
Uncaught TypeError: Cannot set property 'render' of undefined
at normalizeComponent (componentNormalizer.js:24)
我搜索了整个 Internet,但人们只谈论无效导出 class。我确定组件中的有效导出 class。我不知道我做错了什么。
当我回到基于对象的组件时 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
}
EventSignUpForm.vue:
将组件 export
设为 export default
:
export class EventSignUpForm extends Vue
改为
export default class EventSignUpForm extends Vue
并从底部移除
export default EventSignUpForm;
我的同事帮我解决了这个比较棘手的案子。
我们所做的是将 webpack.mix.js 添加到 ts-loader 选项对象。我们需要为 Vue 组件附加 TS 后缀。现在是:
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 中只使用了导入,但必须将其更改为这样:
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 花时间并提供了有效的解决方案:)
我正在使用 Laravel Mix 来编译我的 Vue 组件,为此,我使用了 TypeScript 和基于 class 的组件。每个单独的 class 都是从组件中导出的,并且主应用程序脚本中的上下文需要每个单独的组件,但是在呈现 Vue 时抛出错误。
Uncaught TypeError: Cannot set property 'render' of undefined
at normalizeComponent (componentNormalizer.js:24)
我搜索了整个 Internet,但人们只谈论无效导出 class。我确定组件中的有效导出 class。我不知道我做错了什么。
当我回到基于对象的组件时 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
}
EventSignUpForm.vue:
将组件 export
设为 export default
:
export class EventSignUpForm extends Vue
改为
export default class EventSignUpForm extends Vue
并从底部移除
export default EventSignUpForm;
我的同事帮我解决了这个比较棘手的案子。
我们所做的是将 webpack.mix.js 添加到 ts-loader 选项对象。我们需要为 Vue 组件附加 TS 后缀。现在是:
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 中只使用了导入,但必须将其更改为这样:
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 花时间并提供了有效的解决方案:)