Vue.js 2.5 升级后无法使 Vue.js + TypeScript + RequireJS 堆栈工作
Can't make Vue.js + TypeScript + RequireJS stack work after Vue.js 2.5 upgrade
我有一个使用 Vue.js 2.4 + TypeScript + RequireJS 堆栈的项目需要升级到最新的 Vue.js。升级到 Vue.js 会破坏它,根据文档进行更改后我无法修复此问题。
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vue.js Scratchpad</title>
<link rel="icon" type="image/png" href="favicon.png">
<meta charset="UTF-8">
<script src="node_modules/requirejs/require.js"></script>
</head>
<body>
<h1>Vue.js Scratchpad</h1>
<div v-show="true" id="app" style="display: none">
<input v-model="user" autofocus="true" placeholder="Enter any user name">
<!--<button @click.prevent="onRenderComponent">Render</button>-->
<p v-show="loading">Loading...</p>
<router-view v-show="!loading" :user="user"
@loading="onLoading" @success="onLoaded"
@loading-error="onLoadingError"></router-view>
</div>
<script>
requirejs.config({
// By default load modules from `./`
baseUrl: '.',
/*
By default, modules would be loaded from {module}.js files (filename = module).
Specify {module} (or "{module}"): "{filepath_no_extension}" mapping if filename != module.
Specify fall-backs ([filepath1, filepath2]) for minimized / normal version consumption pattern.
*/
paths: {
// All third-party libraries must be included here. Use path fall-backs for minimized libs.
axios: "node_modules/axios/dist/axios.min",
vue: "node_modules/vue/dist/vue.min",
"vue-router": "node_modules/vue-router/dist/vue-router.min"
}
});
require(["app-pure-vue.js"]);
</script>
</body>
</html>
app-pure-vue.ts:
import * as Vue from "vue";
import * as VueRouter from "vue-router";
import { AxiosError } from "axios";
//region App components
import MessageComponent from "./messageComponent-pure-vue";
//endregion
Vue.use(VueRouter);
const routes = [
{
path: "/",
component: MessageComponent
}
];
const router = new VueRouter({
routes
});
const appOptions = {
router,
data() {
return {
user: null,
loading: false
};
},
methods: {
onLoading() {
// @ts-ignore
this.loading = true;
console.log("Loading...");
},
onLoaded() {
// @ts-ignore
this.loading = false;
console.log("Loaded.");
},
onLoadingError(error: AxiosError, serviceUrl: string) {
// @ts-ignore
this.loading = false;
console.log("Loading error for", serviceUrl, error.response);
}
}
};
new Vue(appOptions).$mount("#app");
messageComponent-纯-vue.ts:
import * as Vue from "vue";
import * as VueRouter from "vue-router";
import { AxiosError } from "axios";
//region App components
import MessageComponent from "./messageComponent-pure-vue";
//endregion
Vue.use(VueRouter);
const routes = [
{
path: "/",
component: MessageComponent
}
];
const router = new VueRouter({
routes
});
const appOptions = {
router,
data() {
return {
user: null,
loading: false
};
},
methods: {
onLoading() {
// @ts-ignore
this.loading = true;
console.log("Loading...");
},
onLoaded() {
// @ts-ignore
this.loading = false;
console.log("Loaded.");
},
onLoadingError(error: AxiosError, serviceUrl: string) {
// @ts-ignore
this.loading = false;
console.log("Loading error for", serviceUrl, error.response);
}
}
};
new Vue(appOptions).$mount("#app");
这个例子运行良好。现在,要升级到 Vue.js
2.5.0 + 最新的 vue-router
,这里是需要记录的更改:
package.json
:更新为 "vue": "~2.5.0"
+ "vue-router": "~3.1.5"
*.ts
: import * as Vue from "vue";
=> import Vue from "vue";
app-pure-vue.ts
: import * as VueRouter from "vue-router";
=> import VueRouter from "vue-router";
代码可以编译,但在 messageComponent-pure-vue.ts
中的 Vue.extend()
:
Uncaught TypeError: Cannot read property 'extend' of undefined
at Object.<anonymous> (messageComponent-pure-vue.ts:5)
你能帮我解决这个问题吗?此处提供了最小的可重现示例:https://github.com/DKroot/Scratchpad/tree/master/Client_Side/Vue.js-2.5. The working 2.4 code is at https://github.com/DKroot/Scratchpad/tree/master/Client_Side/Vue.js-2.4.
到目前为止我在这方面做了什么:
- 已将问题隔离到 2.5.0 升级
- 仔细查看 2.5.0 发行说明 (https://github.com/vuejs/vue/releases/tag/v2.5.0) and the corresponding blog post (https://medium.com/the-vue-point/upcoming-typescript-changes-in-vue-2-5-e9bd7e2ecf08)
- 查看了 2.5.0 中 TypeScript 声明的更改。导出有点太复杂,我无法找出根本原因。
长话短说:
试试这个:
import Vue from "vue";
import VueRouter from "vue-router";
解释:
当一个模块这样写的时候:
// module.ts
export function x() { ... }
export function y() { ... }
您可以像这样导入它:
import * as Module from "./module";
但是当这样写的时候:
// module-with-default.ts
export default class Module {
public static function x() { ... }
public static function y() { ... }
}
你会像这样导入它:
import Module from "./module-with-default";
在这两种情况下,您都可以像这样使用它:
Module.x();
Module.y();
Vue.js 的变化:
这是how it is exported in v2.5.0:
export default Vue
这是is how it is exported in v2.4.0:
export = Vue;
TL;博士
将这些添加到项目中:
// vue-loader.ts
import * as AllVue from "Vue";
import Defaults from "Vue";
export const Vue = AllVue as unknown as Defaults;
export default Vue;
// vue-router-loader.ts
import * as AllVueRouter from "Vue-router";
import Defaults from "Vue-router";
export const Vue = AllVueRouter as unknown as Defaults;
export default Vue;
像这样配置 RequireJS:
paths: {
Vue: "node_modules/vue/dist/vue.min",
vue: "vue-loader",
"Vue-router": "node_modules/vue-router/dist/vue-router.min",
"vue-router": "vue-router-loader"
}
说明
问题是由 TypeScript 如何为具有默认导出的 amd
模块生成 JavaScript 以及 RequireJS 如何加载这些默认导出引起的。
当你这样做时:
import Vue from "vue";
Vue.extend(...);
TypeScript 将其翻译成:
define(["require", "exports", "vue"], function (require, exports, vue_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
vue_1.default.extend(..);
});
注意 .default
部分?问题是 RequireJS,将 vue_1
设置为实际的 default
,因此 vue_1.default
最终成为 undefined
(因此您的原始错误)
当您使用上面的加载程序时,您正在重新导出 *
这实际上是默认导出作为非默认导出和默认导出。这是为 vue-loader.ts
:
生成的代码
define(["require", "exports", "Vue"], function (require, exports, AllVue) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Vue = AllVue; // <--- this resolves your problem
exports.default = exports.Vue;
});
为了使用我们的装载机,我们 "re-routing" 下了决心。因此,如果真实代码尝试要求 vue
,它将转到我们的加载程序,它将加载 Vue
,这是 真实 Vue 代码。
推荐
我想避免这个问题的最好方法是 而不是 使用 RequireJS - 如果你不需要 IE 支持,你可以只做 native module loading 或使用 Webpack
另一种可能的解决方案
看这里:Missing default export when using SystemJS or RequireJS makes Vue unusable with TypeScript
我有一个使用 Vue.js 2.4 + TypeScript + RequireJS 堆栈的项目需要升级到最新的 Vue.js。升级到 Vue.js 会破坏它,根据文档进行更改后我无法修复此问题。
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vue.js Scratchpad</title>
<link rel="icon" type="image/png" href="favicon.png">
<meta charset="UTF-8">
<script src="node_modules/requirejs/require.js"></script>
</head>
<body>
<h1>Vue.js Scratchpad</h1>
<div v-show="true" id="app" style="display: none">
<input v-model="user" autofocus="true" placeholder="Enter any user name">
<!--<button @click.prevent="onRenderComponent">Render</button>-->
<p v-show="loading">Loading...</p>
<router-view v-show="!loading" :user="user"
@loading="onLoading" @success="onLoaded"
@loading-error="onLoadingError"></router-view>
</div>
<script>
requirejs.config({
// By default load modules from `./`
baseUrl: '.',
/*
By default, modules would be loaded from {module}.js files (filename = module).
Specify {module} (or "{module}"): "{filepath_no_extension}" mapping if filename != module.
Specify fall-backs ([filepath1, filepath2]) for minimized / normal version consumption pattern.
*/
paths: {
// All third-party libraries must be included here. Use path fall-backs for minimized libs.
axios: "node_modules/axios/dist/axios.min",
vue: "node_modules/vue/dist/vue.min",
"vue-router": "node_modules/vue-router/dist/vue-router.min"
}
});
require(["app-pure-vue.js"]);
</script>
</body>
</html>
app-pure-vue.ts:
import * as Vue from "vue";
import * as VueRouter from "vue-router";
import { AxiosError } from "axios";
//region App components
import MessageComponent from "./messageComponent-pure-vue";
//endregion
Vue.use(VueRouter);
const routes = [
{
path: "/",
component: MessageComponent
}
];
const router = new VueRouter({
routes
});
const appOptions = {
router,
data() {
return {
user: null,
loading: false
};
},
methods: {
onLoading() {
// @ts-ignore
this.loading = true;
console.log("Loading...");
},
onLoaded() {
// @ts-ignore
this.loading = false;
console.log("Loaded.");
},
onLoadingError(error: AxiosError, serviceUrl: string) {
// @ts-ignore
this.loading = false;
console.log("Loading error for", serviceUrl, error.response);
}
}
};
new Vue(appOptions).$mount("#app");
messageComponent-纯-vue.ts:
import * as Vue from "vue";
import * as VueRouter from "vue-router";
import { AxiosError } from "axios";
//region App components
import MessageComponent from "./messageComponent-pure-vue";
//endregion
Vue.use(VueRouter);
const routes = [
{
path: "/",
component: MessageComponent
}
];
const router = new VueRouter({
routes
});
const appOptions = {
router,
data() {
return {
user: null,
loading: false
};
},
methods: {
onLoading() {
// @ts-ignore
this.loading = true;
console.log("Loading...");
},
onLoaded() {
// @ts-ignore
this.loading = false;
console.log("Loaded.");
},
onLoadingError(error: AxiosError, serviceUrl: string) {
// @ts-ignore
this.loading = false;
console.log("Loading error for", serviceUrl, error.response);
}
}
};
new Vue(appOptions).$mount("#app");
这个例子运行良好。现在,要升级到 Vue.js
2.5.0 + 最新的 vue-router
,这里是需要记录的更改:
package.json
:更新为"vue": "~2.5.0"
+"vue-router": "~3.1.5"
*.ts
:import * as Vue from "vue";
=>import Vue from "vue";
app-pure-vue.ts
:import * as VueRouter from "vue-router";
=>import VueRouter from "vue-router";
代码可以编译,但在 messageComponent-pure-vue.ts
中的 Vue.extend()
:
Uncaught TypeError: Cannot read property 'extend' of undefined
at Object.<anonymous> (messageComponent-pure-vue.ts:5)
你能帮我解决这个问题吗?此处提供了最小的可重现示例:https://github.com/DKroot/Scratchpad/tree/master/Client_Side/Vue.js-2.5. The working 2.4 code is at https://github.com/DKroot/Scratchpad/tree/master/Client_Side/Vue.js-2.4.
到目前为止我在这方面做了什么:
- 已将问题隔离到 2.5.0 升级
- 仔细查看 2.5.0 发行说明 (https://github.com/vuejs/vue/releases/tag/v2.5.0) and the corresponding blog post (https://medium.com/the-vue-point/upcoming-typescript-changes-in-vue-2-5-e9bd7e2ecf08)
- 查看了 2.5.0 中 TypeScript 声明的更改。导出有点太复杂,我无法找出根本原因。
长话短说:
试试这个:
import Vue from "vue";
import VueRouter from "vue-router";
解释:
当一个模块这样写的时候:
// module.ts
export function x() { ... }
export function y() { ... }
您可以像这样导入它:
import * as Module from "./module";
但是当这样写的时候:
// module-with-default.ts
export default class Module {
public static function x() { ... }
public static function y() { ... }
}
你会像这样导入它:
import Module from "./module-with-default";
在这两种情况下,您都可以像这样使用它:
Module.x();
Module.y();
Vue.js 的变化:
这是how it is exported in v2.5.0:
export default Vue
这是is how it is exported in v2.4.0:
export = Vue;
TL;博士
将这些添加到项目中:
// vue-loader.ts
import * as AllVue from "Vue";
import Defaults from "Vue";
export const Vue = AllVue as unknown as Defaults;
export default Vue;
// vue-router-loader.ts
import * as AllVueRouter from "Vue-router";
import Defaults from "Vue-router";
export const Vue = AllVueRouter as unknown as Defaults;
export default Vue;
像这样配置 RequireJS:
paths: {
Vue: "node_modules/vue/dist/vue.min",
vue: "vue-loader",
"Vue-router": "node_modules/vue-router/dist/vue-router.min",
"vue-router": "vue-router-loader"
}
说明
问题是由 TypeScript 如何为具有默认导出的 amd
模块生成 JavaScript 以及 RequireJS 如何加载这些默认导出引起的。
当你这样做时:
import Vue from "vue";
Vue.extend(...);
TypeScript 将其翻译成:
define(["require", "exports", "vue"], function (require, exports, vue_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
vue_1.default.extend(..);
});
注意 .default
部分?问题是 RequireJS,将 vue_1
设置为实际的 default
,因此 vue_1.default
最终成为 undefined
(因此您的原始错误)
当您使用上面的加载程序时,您正在重新导出 *
这实际上是默认导出作为非默认导出和默认导出。这是为 vue-loader.ts
:
define(["require", "exports", "Vue"], function (require, exports, AllVue) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Vue = AllVue; // <--- this resolves your problem
exports.default = exports.Vue;
});
为了使用我们的装载机,我们 "re-routing" 下了决心。因此,如果真实代码尝试要求 vue
,它将转到我们的加载程序,它将加载 Vue
,这是 真实 Vue 代码。
推荐
我想避免这个问题的最好方法是 而不是 使用 RequireJS - 如果你不需要 IE 支持,你可以只做 native module loading 或使用 Webpack
另一种可能的解决方案
看这里:Missing default export when using SystemJS or RequireJS makes Vue unusable with TypeScript