Struggling to get the Vue.js + TypeScript + RequireJS stack functioning properly post Vue.js 2.5 upgrade

I am currently working on a project that uses the Vue.js 2.4 + TypeScript + RequireJS stack and I need to upgrade it to the latest version of Vue.js. However, after making the necessary changes according to the documentation, the upgrade breaks the project and I have been unable to resolve the issue.

Here is the code snippet from 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>

// More code here...

app-pure-vue.ts:

// TypeScript code for app here...

messageComponent-pure-vue.ts:

// TypeScript code for message component here...

In order to upgrade to Vue.js 2.5.0 and the latest vue-router, certain documented changes are required as follows:

  1. package.json: Update to "vue": "~2.5.0" + "vue-router": "~3.1.5"
  2. *.ts: Change import * as Vue from "vue"; to import Vue from "vue";
  3. app-pure-vue.ts: Change
    import * as VueRouter from "vue-router";
    to
    import VueRouter from "vue-router";

Despite these changes, when upgrading to Vue.js 2.5.0, an error occurs at Vue.extend() in messageComponent-pure-vue.ts:

Uncaught TypeError: Cannot read property 'extend' of undefined
    at Object.<anonymous> (messageComponent-pure-vue.ts:5)

If you can offer assistance in resolving this issue, please take a look at the minimal reproducible example provided here: https://github.com/DKroot/Scratchpad/tree/master/Client_Side/Vue.js-2.5. The original working 2.4 code can also be found at https://github.com/DKroot/Scratchpad/tree/master/Client_Side/Vue.js-2.4.

Steps taken so far to address the issue:

  1. Confirmed that the problem arises specifically with the 2.5.0 upgrade
  2. Carefully reviewed release notes for version 2.5.0 (https://github.com/vuejs/vue/releases/tag/v2.5.0) and related blog posts (https://medium.com/the-vue-point/upcoming-typescript-changes-in-vue-2-5-e9bd7e2ecf08)
  3. Explored changes in TypeScript declarations for 2.5.0, but struggled to pinpoint the root cause due to complex exports

Answer №1

TL;DR:

If you encounter a module written like this:

import Vue from "vue";
import VueRouter from "vue-router";

Explanation:

In cases where a module is structured as follows:

// module.ts
export function x() { ... }
export function y() { ... }

You can import it using:

import * as Module from "./module";

However, if the module is structured differently like below:

// module-with-default.ts
export default class Module {
  public static function x() { ... }
  public static function y() { ... }
}

You would need to import it in the following way:

import Module from "./module-with-default";

In both scenarios, you will be able to utilize it as shown here:

Module.x();
Module.y();

Changes in Vue.js:

The export mechanism in v2.5.0 looks like this:

export default Vue

while in v2.4.0, it appears like so:

export = Vue;

Answer №2

Summary

Here are the necessary additions for your project:

// 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;

configure RequireJS like this:

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"
}

Explanation

The issue arises from how TypeScript compiles JavaScript for an amd module with default exports, and how RequireJS handles loading those default exports.

When you write:

import Vue from "vue";

Vue.extend(...);

TypeScript converts it to:

define(["require", "exports", "vue"], function (require, exports, vue_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    vue_1.default.extend(..);
});

This causes an issue because RequireJS sets vue_1 as the actual default, leading to vue_1.default being undefined (resulting in the error).

By using the provided loaders, both the non-default export and the default export (denoted by *) are re-exported, resolving the problem:

define(["require", "exports", "Vue"], function (require, exports, AllVue) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.Vue = AllVue; // <--- this solves the issue
    exports.default = exports.Vue;
});

We're essentially redirecting the resolution with our loaders, ensuring that requiring vue will load the proper Vue code.

Recommendation

To avoid this problem, consider not using RequireJS - if IE support is unnecessary, native module loading or Webpack could be viable alternatives.

Another potential solution

Check out this resource: Missing default export when using SystemJS or RequireJS makes Vue unusable with TypeScript

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Elements are automatically removed from default.vue once they have been compiled in Nuxt

Looking to add a header in my Nuxt application within Nuxt/layouts/default.vue <template> <div> <Navigation/> <Nuxt /> </div> </template> But the code: <template> <Nuxt /> </template> ...

Issue encountered while executing the Docker run command: EEXIST - The file already exists as a symbolic link from '/app/node_modules' to '/app/.build/node_modules'

I've encountered an issue while trying to run a Node.js TypeScript app with Docker. The Dockerfile I'm using builds the image successfully: FROM lambci/lambda:build-nodejs6.10 # Set up the app directory WORKDIR /app # Install app dependencies ...

Ensuring that the keys within an array in an object literal are limited to those present in the outer object

These are the Interface definitions that I currently have: interface IComponents { root: IComponent, [key: string]: IComponent, } interface IComponent { type: string, children?: Array<keyof IComponents>; } I need to restrict the "children" ...

How to pass route parameters using v-link in Vue Router

Within the Parent.vue file, I have included this anchor tag: <a v-link="{ path: '/somepath/somesubpath', query: { messageId: 999}}"> Here </a> And also this one: <a v-link="{ path: '/somepath/somesubpath', params: { me ...

Unable to locate module src/ in Node.js TypeScript

I'm encountering issues with non-relative imports in my node.js / typescript application. Here is my tsconfig: { "compilerOptions": { "target": "es6", "module": "commonjs", "lib": ["dom", "es6", "es2017", "esnext.asynciterable"], "s ...

Develop a React component with TypeScript that defines specific props in its interface, allowing its parent component to provide those props

I am looking to create a custom MenuButton interface that includes an "isMenuOpen" property, which can be provided by its parent component. function Menu({ SomeButton }: { SomeButton: MenuButton }) { const [isOpen, setIsOpen] = useState(false) retur ...

Get the JSON file from Firebase storage

My query boils down to this: Within my vue.js application, I am uploading a json file to a firebase storage bucket. However, when attempting to download the file for use within the app, I encounter an "Uncaught (in promise) undefined" error. The goal is t ...

Is there a way to prompt TypeScript to report an error when a mapped key is missing?

Here is my current code snippet: type TransferType = 'INTERNAL' | 'WITHDRAWAL' | 'DEPOSIT' type TransferEvents = Record<TransferType, Record<string, TypeFoo | TypeBar>> export interface EventsTooltip extends Tran ...

Understanding how Vue CLI v3 determines which JavaScript files should be separated into different chunks

Struggling to grasp the new CLI and configuration adjustments. The official documentation lacks details on incorporating CSS as an entry point instead of directly importing it into a component or main.js. Noticing that some JS files are being split into s ...

Exploring the functionality of select box options in Vue

I recently set up a select box in Vue using the following code: <select name="count" @change="change($event)"> <option value="a">one</option> <option value="b">two</option> <opt ...

Oops! It seems like the module 'webpack/lib/rules/DescriptionDataMatcherRulePlugin' cannot be located. This may be due to a missing dependency

Within my Laravel project, webpack-cli is installed. I am uncertain why it is necessary to run my Vue app, but encountering the following error: Whenever I try to execute npm run dev or npm run hot [webpack-cli] Error: Cannot find module 'webpack/lib ...

The correct way to integrate CSS-Modules into your Nuxt project

Currently, I am utilizing CSS Modules with Nuxt and have encountered some challenges while attempting to import a stylesheet into my JavaScript. Importing the stylesheet directly within the... <style module> @import './index.css'; </s ...

I keep receiving error code TS2339, stating that property 'total' is not recognized within type any[]

Check out this code snippet. Can you provide some assistance? responseArray: any[] = []; proResponseArray: any[] = []; clearArray(res: any[]): void {res.length = 0; this.response.total = 0; } handleSubmit(searchForm: FormGroup) { this.sho ...

Trouble with Vue images not displaying

I'm encountering an issue with displaying images in my Vue CLI project. Here's the situation: this particular Vue file is accessing a JSON file that contains references to individual Eyewear objects, which is all functioning correctly. The JSON ...

Getting into a slot within a nested component within the render function

Currently using Vue 3 and I have a component with a render() function structured like this: render() { return ( <my-component> <div ref="cont" slot="cont">content</div> <my-component> ) } In addition, w ...

Learn how to trigger an HTTP exception after a failed command in a saga with NestJS CQRS

Currently utilizing the NestJS CQRS pattern to handle interactions between User and UserProfile entities within my system. The setup consists of an API Gateway NestJS server along with dedicated NestJS servers for each microservice (User, UserProfile, etc. ...

Executing a function prior to signing up

Is there a way to dynamically add a form control once the user has made a selection? This is my select function: selected(event: MatAutocompleteSelectedEvent): void { this.setTechnologies = new Set(); this.setTechnologies.add(this.techInput.n ...

Status:0 was received as the response from URL:null during the REST call made from my iOS Ionic application

I am currently facing an issue with a rest call in my Ionic app. The call works fine on Android devices but encounters problems on iOS devices. Below is the implementation of the rest call in my Ionic service. import { Http } from '@angular/http&apos ...

The type 'ssr' is not found within the 'ResourcesConfig | LegacyConfig | AmplifyOutputs' interface. Error code: ts(2353)

I've been following a step-by-step tutorial (check it out here at 2:25:16) on creating a full stack application, but I've hit a roadblock when trying to enable SSR. import "@/styles/globals.css"; import type { AppProps } from "next ...

Unable to install vue-property-decorator

When attempting to set up Vue and TypeScript with class style using vue-property-decorator, I encountered a strange script after creating the project. I was anticipating a script like this: <script lang="ts"> import {Component, Vue} from & ...