javascript - TypeScript 无法检测 *.vue 文件

标签 javascript typescript webpack vue.js

请帮忙。我似乎无法让 Vue 检测我的单文件组件。

错误消息:

ERROR in ./src/App.vue (./node_modules/ts-loader!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/App.vue)
Module build failed: Error: Could not find file: 'F:\Projects\core\client\src\App.vue'.
    at getValidSourceFile (F:\Projects\core\client\node_modules\typescript\lib\typescript.js:107554:23)
    at Object.getEmitOutput (F:\Projects\core\client\node_modules\typescript\lib\typescript.js:108052:30)
    at Object.getEmitOutput (F:\Projects\core\client\node_modules\ts-loader\dist\instances.js:187:41)
    at getEmit (F:\Projects\core\client\node_modules\ts-loader\dist\index.js:196:37)
    at successLoader (F:\Projects\core\client\node_modules\ts-loader\dist\index.js:34:11)
    at Object.loader (F:\Projects\core\client\node_modules\ts-loader\dist\index.js:21:12)
 @ ./src/App.vue 7:0-97 7:0-97 8:0-110 21:2-16
 @ ./src/index.ts
 @ multi (webpack)-dev-server/client?http://localhost:9000 webpack/hot/dev-server ./src/index.ts

我还按照其他帖子的建议添加了 vue-shims.d.ts 文件。

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

tsconfig.json

{
  "compilerOptions": {
    // this aligns with Vue's browser support
    "target": "es5",
    // this enables stricter inference for data properties on `this`
    "strict": true,
    // if using webpack 2+ or rollup, to leverage tree shaking:
    "module": "es2015",
    "moduleResolution": "node",
    "lib": [ "es2015", "es2017", "es6", "dom", "es2015.iterable" ],
    "noImplicitAny": true,
    "strictNullChecks": true,
    "allowSyntheticDefaultImports": true
  }
}

如果我将导入更改为 ./App.vue.d 那么它就可以工作,但显然导入类型文件不会为您提供所需文件的实际内容。

App.vue

<template>
    <div class="height-100 width-100">
        <div class="app-container height-100 width-100">
            <router-view></router-view>
        </div>
        <offline-notice></offline-notice>
    </div>
</template>

<script lang="ts">
    import Vue from "vue"

    export default Vue.extend({
        components: {
            "offline-notice": () => import("../src/components/common/OfflineNotice.vue")
        }
    })
</script>

<style lang="sass">
    @import "assets/stylesheets/variables"
    @import "assets/stylesheets/base"
    @import "assets/stylesheets/helpers"
    @import "../node_modules/izitoast/dist/css/iziToast.min.css"
    @import "assets/stylesheets/components/notifications"
</style>

index.ts

import Vue from "vue"
import VueRouter from "vue-router"
import "element-ui/lib/theme-chalk/index.css"
import "./assets/stylesheets/vendor/ionicons.min.scss"
import "babel-polyfill"

import { store } from "./store"
import { routes } from "./routes/routes-setup"
import { setupSelectedElementUIComponents } from "../config/element-ui-helper"

import App from "./App.vue"

Vue.use(VueRouter)

setupSelectedElementUIComponents(Vue)

const router = new VueRouter({
    routes,
    scrollBehavior(to, from, savedPosition) {
        if (savedPosition) {
            return savedPosition
        }
        if (to.hash) {
            return {selector: to.hash}
        }
    }
})

// noinspection TsLint
new Vue({
    el: "#app",
    router,
    store,
    render: h => h(App),
})

我的基本 webpack 配置:

const ExtractTextPlugin = require("extract-text-webpack-plugin")
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin")

module.exports = {
    entry: {
        main: "./src/index.ts",
        vendor: [
            "string-format",
            "element-ui",
            "izitoast",
            "vue-swal",
            "vue",
            "axios",
            "croppie",
            "vue-router",
            "vuex",
            "vuex-persistedstate",
        ]
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                exclude: /node_modules|vue\/src/,
                loader: "ts-loader",
                options: {
                    appendTsSuffixTo: [/\.vue$/]
                }
            },
            {
                test: /\.vue$/,
                loader: "vue-loader",
                options: {
                    esModule: true
                }
            },
            {
                test: /\.tsx?$/,
                loader: 'ts-loader',
                exclude: /node_modules/,
                options: {
                    appendTsSuffixTo: [/\.vue$/],
                }
            },
            {
                test: /\.js$/,
                loader: "babel-loader",
                exclude: /node_modules/
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: "file",
                options: {
                    name: "[name].[ext]?[hash]"
                }
            },
            {
                test: /\.css$/,
                use: ["style-loader", "css-loader"]
            },
            {
                test: /\.(scss|sass)$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: ["css-loader", "sass-loader"]
                })
            },
            {
                // Match woff2 in addition to patterns like .woff?v=1.1.1.
                test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
                loader: "url-loader",
                options: {
                    // Limit at 50k. Above that it emits separate files
                    limit: 50000,

                    // url-loader sets mimetype if it"s passed.
                    // Without this it derives it from the file extension
                    mimetype: "application/font-woff",

                    // Output below fonts directory
                    name: "./fonts/[name].[ext]"
                }
            },
            {
                test: /\.(ttf|eot|woff|woff2)$/,
                loader: "file-loader",
                options: {
                    name: "fonts/[name].[ext]"
                }
            },
        ]
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        },
        extensions: [".js", ".vue", ".json", ".scss", ".sass", ".ts"]
    },
    optimization: {
        splitChunks: {
            chunks: "async",
            minChunks: 1,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            name: true,
            cacheGroups: {
                default: {
                    minChunks: 2,
                    priority: -20,
                    reuseExistingChunk: true
                },
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10
                }
            }
        }
    },
    plugins: [
        new ExtractTextPlugin({
            filename: "[name].[hash].css"
        }),
        new ForkTsCheckerWebpackPlugin({
            vue: true,
        })
    ]
}

最佳答案

这就是我最终的工作。

"vue-loader": "^14.2.2", 升级到 "vue-loader": "^15.2.4", 并添加 VueLoaderPlugin 插件到我的 webpack 配置 (Webpack 4)。

webpack.common.js

const {VueLoaderPlugin} = require('vue-loader')
...
plugins: [
    new ExtractTextPlugin({
        filename: "[name].[hash].css"
    }),
    // new ForkTsCheckerWebpackPlugin({
    //     vue: true,
    // }),
    new VueLoaderPlugin()
]

关于javascript - TypeScript 无法检测 *.vue 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51024076/

相关文章:

typescript - 映射 typescript 类型

javascript - 如何在 webpack 中运行 run --history-api-fallback

javascript - Angular 10 没有 ModalDialogService 的提供者

reactjs - 使用 webpack 插件进行 Mocha 测试

javascript - 为什么我不能渲染这个 angularJS 代码?

javascript - Html 5视频停止事件

javascript - 提交表单 Angular 后如何显示用户名

javascript - 如何在vue js中设置一天的默认日期

Javascript Promise 循环多次

angular - NgbModal - 自定义类样式