Karma/Webpack/Vue.js: 属性 或方法未在实例上定义但在渲染期间被引用
Karma/Webpack/Vue.js: Property or method is not defined on the instance but referenced during render
我看到这个问题已经被问过很多次了,但在这种情况下,我认为它与我的 karma/webpack 配置相关,而不是我在 Vue 中所做的事情。那是因为我只在 运行 使用 Karma 进行测试(使用最新的 Chrome headless)时收到警告,但在使用 webpack-dev-server马上。
这是我的配置文件,从 app/webpack.base.config.js 文件开始:
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css/,
loader: 'style-loader!css-loader'
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader'
}, {
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
};
app/webpack.config.js
const path = require('path');
const webpack = require('webpack');
const mergeConfig = require('webpack-merge');
const baseConfig = require('./webpack.base.config');
module.exports = mergeConfig(baseConfig, {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
devServer: {
historyApiFallback: true,
noInfo: true,
hot: true
},
performance: {
hints: false
},
devtool: '#eval-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
app/test/karma.conf.js(这里只使用了webpack.base.config.js文件,不是全部)
// Karma configuration
const webpackConfig = require('../webpack.base.config');
process.env.CHROME_BIN = require('puppeteer').executablePath();
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '.',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'./index.js'
],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'./index.js': ['webpack']
},
// karma watches the test entry points
// (you don't need to specify the entry option)
// webpack watches dependencies
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['spec'],
// web server port
port: 8080,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['ChromeHeadlessNoSandbox'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
},
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: 1
});
};
app/test/index.js
import Vue from 'vue';
Vue.config.productionTip = false;
// require all test files (files that ends with .js)
const testsContext = require.context('./specs', true, /\.js/);
testsContext.keys().forEach(testsContext);
然后我在我的规格中安装组件时收到警告,如下所示:
import Vue from 'vue';
import Extractor from './../../../src/components/Extractor.vue';
describe('Extractor component', () => {
it('sets the correct default data', () => {
const component = new Vue(Extractor).$mount();
expect(component.url).toBe('');
expect(component.responseCode).toBe(null);
expect(component.body).toBe(null);
expect(component.errorMessage).toBe(null);
});
});
警告:这种情况发生仅如果:
- 我使用 vue-class-component 库
- 我的组件继承自另一个
- 当运行代码通过Karma/Chrome headless
我在日志中得到的错误是:
[Vue warn]: Property or method "valid" 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. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
它抱怨的 "valid" 属性 在 ApiComponent
class 里面(基本上是父类)。
这是给我警告的组件之一:
import http from './../modules/http';
import ApiComponent from './sub/ApiComponent';
import Component from 'vue-class-component';
// @see https://github.com/vuejs/vue-class-component
// @see https://github.com/wycats/javascript-decorators/blob/master/README.md
@Component()
export default class Extractor extends ApiComponent {
url = '';
sendRequest() {
return new Promise((resolve, reject) => {
// some AJAX call here
});
}
}
如果不是让 Extractor
从 ApiComponent
扩展,我让它扩展 Vue
class 并复制并粘贴所有 ApiComponent
代码在 Extractor
class 内,警告消失。关键是...为什么只有当 运行 代码通过 Karma 时我才会收到警告?
装饰超级 class (ApiComponent
).
警告消失
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default class ApiComponent extends Vue {
// ...
}
我看到这个问题已经被问过很多次了,但在这种情况下,我认为它与我的 karma/webpack 配置相关,而不是我在 Vue 中所做的事情。那是因为我只在 运行 使用 Karma 进行测试(使用最新的 Chrome headless)时收到警告,但在使用 webpack-dev-server马上。
这是我的配置文件,从 app/webpack.base.config.js 文件开始:
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css/,
loader: 'style-loader!css-loader'
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader'
}, {
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
};
app/webpack.config.js
const path = require('path');
const webpack = require('webpack');
const mergeConfig = require('webpack-merge');
const baseConfig = require('./webpack.base.config');
module.exports = mergeConfig(baseConfig, {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
devServer: {
historyApiFallback: true,
noInfo: true,
hot: true
},
performance: {
hints: false
},
devtool: '#eval-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
app/test/karma.conf.js(这里只使用了webpack.base.config.js文件,不是全部)
// Karma configuration
const webpackConfig = require('../webpack.base.config');
process.env.CHROME_BIN = require('puppeteer').executablePath();
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '.',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'./index.js'
],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'./index.js': ['webpack']
},
// karma watches the test entry points
// (you don't need to specify the entry option)
// webpack watches dependencies
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['spec'],
// web server port
port: 8080,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['ChromeHeadlessNoSandbox'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
},
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: 1
});
};
app/test/index.js
import Vue from 'vue';
Vue.config.productionTip = false;
// require all test files (files that ends with .js)
const testsContext = require.context('./specs', true, /\.js/);
testsContext.keys().forEach(testsContext);
然后我在我的规格中安装组件时收到警告,如下所示:
import Vue from 'vue';
import Extractor from './../../../src/components/Extractor.vue';
describe('Extractor component', () => {
it('sets the correct default data', () => {
const component = new Vue(Extractor).$mount();
expect(component.url).toBe('');
expect(component.responseCode).toBe(null);
expect(component.body).toBe(null);
expect(component.errorMessage).toBe(null);
});
});
警告:这种情况发生仅如果:
- 我使用 vue-class-component 库
- 我的组件继承自另一个
- 当运行代码通过Karma/Chrome headless
我在日志中得到的错误是:
[Vue warn]: Property or method "valid" 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. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
它抱怨的 "valid" 属性 在 ApiComponent
class 里面(基本上是父类)。
这是给我警告的组件之一:
import http from './../modules/http';
import ApiComponent from './sub/ApiComponent';
import Component from 'vue-class-component';
// @see https://github.com/vuejs/vue-class-component
// @see https://github.com/wycats/javascript-decorators/blob/master/README.md
@Component()
export default class Extractor extends ApiComponent {
url = '';
sendRequest() {
return new Promise((resolve, reject) => {
// some AJAX call here
});
}
}
如果不是让 Extractor
从 ApiComponent
扩展,我让它扩展 Vue
class 并复制并粘贴所有 ApiComponent
代码在 Extractor
class 内,警告消失。关键是...为什么只有当 运行 代码通过 Karma 时我才会收到警告?
装饰超级 class (ApiComponent
).
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default class ApiComponent extends Vue {
// ...
}