简体   繁体   中英

Using Typescript with Laravel and Vue.js, imports not making it to Vue components?

I'm trying to write a Vue SPA with a Laravel Backend, while also using Typescript instead of Raw Javascript. I think I'm having trouble wrapping my head around certain things, mostly surrounding typescript. Obviously I need Axios, so I attempted to import it and bind it to the Window in my bootstrap.ts file similar to the way it was done in Laravel's default bootstrap.js file.

resources/js/bootstrap.ts

import 'bootstrap';
import Axios, {AxiosStatic} from 'axios';

declare global {
    // Extending the DOM Window Interface
    interface Window {
        axios: AxiosStatic;
    }

    // Extending querySelector Element
    interface Element {
        content: string;
    }
}

declare var window: Window;
window.axios = Axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

const token: Element | null = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token')
}

That then gets imported to my app.ts file, which then sets up the Vue Router and imports the components.

resources/js/app.ts

/**
 * First, we will load all of this project's Javascript utilities and other
 * dependencies. Then, we will be ready to develop a robust and powerful
 * application frontend using useful Laravel and JavaScript libraries.
 */

import './bootstrap';
import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

import App from './views/App.vue';
import Welcome from './views/Welcome.vue';
import Dashboard from './views/Dashboard.vue';
import Login from './views/Login.vue';
import Register from './views/Register.vue';

const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            name: 'home',
            component: Welcome
        },
        {
            path: '/login',
            name: 'login',
            component: Login
        },
        {
            path: '/register',
            name: 'register',
            component: Register
        },
        {
            path: '/dashboard',
            name: 'dashboard',
            component: Dashboard
        }
    ],
});

const app = new Vue({
    el: '#app',
    components: { App },
    router,
});

However, when I attempt to use axios in my Vue components, I get the error cannot find name 'axios' . Of course I also get errors related to implicit any typings but I'm aware of why I'm getting those. Of course I also did remember to install axios from npm.

I'll post the Register.vue file here for reference, but I'm getting similar errors in any file I want to use axios in.

resources/js/views/Register.vue

<template>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card card-default">
                    <div class="card-header">Register</div>

                    <div class="card-body">
                        <form method="POST" action="/register">
                            <div class="form-group row">
                                <label for="name" class="col-md-4 col-form-label text-md-right">Name</label>

                                <div class="col-md-6">
                                    <input id="name" type="text" class="form-control" v-model="name" required autofocus>
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="email" class="col-md-4 col-form-label text-md-right">E-Mail Address</label>

                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control" v-model="email" required>
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">Password</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control" v-model="password" required>
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password-confirm" class="col-md-4 col-form-label text-md-right">Confirm Password</label>

                                <div class="col-md-6">
                                    <input id="password-confirm" type="password" class="form-control" v-model="password_confirmation" required>
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-6 offset-md-4">
                                    <button type="submit" class="btn btn-primary" @click="handleSubmit">
                                        Register
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { Route } from 'vue-router'

@Component
export default class Register extends Vue{
        name: string = ""
        email: string = ""
        password: string = ""
        password_confirmation: string = ""

        handleSubmit(e: UIEvent) {
            e.preventDefault()

            if (this.password === this.password_confirmation && this.password.length > 0)
            {
                axios.post('api/register', {
                    name: this.name,
                    email: this.email,
                    password: this.password,
                    c_password : this.password_confirmation
                    })
                    .then((response) => {
                    localStorage.setItem('user',response.data.success.name)
                    localStorage.setItem('jwt',response.data.success.token)

                    if (localStorage.getItem('jwt') != null){
                        this.$router.push('/dashboard', () => this.$router.go(0))
                    }
                    })
                    .catch(error => {
                    console.error(error);
                    });
            } else {
                this.password = ""
                this.password_confirmation = ""

                return alert('Passwords do not match')
            }
        }

        beforeRouteEnter (to: Route, from: Route, next: any) {
            if (localStorage.getItem('jwt')) {
                return next('dashboard');
            }

            next();
        }
}
</script>

Am I missing something obvious here? Going about this the wrong way? Here are some other miscellaneous files that may be relevant to the situation.

webpack.mix.js

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.ts('resources/js/app.ts', 'public/js')
   .sass('resources/sass/app.scss', 'public/css');

tsconfig.json

{
    "compilerOptions": {
        "target": "es5",
        "strict": true,
        "module": "es2015",
        "moduleResolution": "node",
        "experimentalDecorators": true,
    },
    "include": [
        "resources/js/**/*"
    ]
}

resources/js/typings.d.ts

declare module '*.vue' {
    import Vue from 'vue';
    export default Vue;
}

I did not get this to work either, what worked for me is just importing axios in every component, whenever I use axios.

import axios from 'axios';
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
const token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

No everytime you use axios somewhere else, these headers will still be set. For instance in your Register.vue, you would just import axios from 'axios';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM