使用 webpack 时 Vue 路由不起作用。主页可以工作,但子路径 404

问题描述 投票:0回答:1

在使用 webpack 之前,我的 vue 路由工作得很好。然而,我开始遇到一堆加载器问题,因此决定使用 webpack。然而,在我的 webpack 运行后,主页加载正常,但我所有的路由现在都是 404。所有被注释掉的东西都是我已经尝试过的,但没有工作。我相信我的 webpack 配置文件有问题,但我无法弄清楚。任何想法或帮助将不胜感激。谢谢您的宝贵时间。

应用程序.vue

<template>
  <div class="base-app">
    <div class="mapbox" id="mapbox">
      <router-view />
    </div>
  </div>
</template>

<script>
// import Login from './components/login.vue';
// import Tract from './components/tract.vue';

export default {
  name: "App",
  // components: {
  //   Login,
  //   Tract
  // }
};
</script>

路由器.js

import { createWebHistory, createRouter } from "vue-router";
import Index from "./components/index.vue";
import Login from "./components/login.vue";
import Tract from "./components/tract.vue";

const routes =  [
  {
    path: "/",
    component: Index
  },
  {
    path: "/login",
    component: Login
  },
  {
    path: "/tract/:id",
    component: Tract
  }
];


const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

main.js

import { createApp } from 'vue';
import App from './App.vue';
// import login from './components/login.vue';
// import tract from './components/tract.vue';
import router from './router.js';

import "./assets/styles/normalize.css";
import "./assets/styles/app.css"; 

const app = createApp(App);
// app.component('login', login);
// app.component('tract', tract);
app.use(router);
app.mount('#app');

webpack.config.cjs

const { VueLoaderPlugin } = require("vue-loader");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const htmlWebpackPlugin = require("html-webpack-plugin");
const autoprefixer = require("autoprefixer");
const path = require("path");

module.exports = {
  entry: {
    main: "./src/main.js",
  },
  output: {
    filename: 'main.bundle.js',
    path: path.resolve(__dirname, 'dist/')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /\.vue$/,
        loader: "vue-loader",
      },
      {
        test: /\.s?css$/,
        use: [
          "style-loader",
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              esModule: false,
            },
          },
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: () => [autoprefixer()],
              }
            },
          },
          "sass-loader",
        ],
      },
      {
        test: /\.m?js/,
        resolve: {
          fullySpecified: false,
        },
      }
    ],
  },
  plugins: [
    new VueLoaderPlugin(),
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: "[name].[contenthash:8].css",
      chunkFilename: "[name].[contenthash:8].css",
    }),
    new htmlWebpackPlugin({
      template: path.resolve(__dirname, "public", "index.html"),
      favicon: "./public/favicon.ico",
    }),
  ],
  resolve: {
    extensions: [ '.tsx', '.ts', '.js', '.vue' ],
    alias: {
        'vue': '@vue/runtime-dom'
    }
  },
  devtool: 'source-map'
};

vue.config.cjs

module.exports = {
  devServer: {
    disableHostCheck: true,
    devMiddleware: {
      writeToDisk: false
    }
  }
}

package.json

{
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "startdev": "webpack-dev-server --mode development --config ./webpack.config.cjs",
    "start": "NODE_ENV=production webpack --config ./webpack.config.cjs"
  },
  "dependencies": {
    "@aws-amplify/ui-vue": "^3.1.20",
    "aws-amplify": "^5.3.3",
    "axios": "^0.22.0",
    "bootstrap": "4.6.0",
    "chart.js": "^4.4.0",
    "core-js": "^3.34.0",
    "jquery": "^3.6.0",
    "mapbox-gl": "^2.6.0",
    "popper.js": "^1.16.1",
    "postcss-loader": "^7.3.3",
    "vue": "^3.0.0",
    "vue-chartjs": "^5.2.0",
    "vue-router": "4"
  },
  "devDependencies": {
    "@babel/core": "^7.23.5",
    "@babel/preset-env": "^7.23.5",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "autoprefixer": "^10.4.16",
    "babel-loader": "^9.1.3",
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^6.8.1",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.5.4",
    "mini-css-extract-plugin": "^2.7.6",
    "postcss": "^8.4.32",
    "sass": "^1.69.5",
    "sass-loader": "^13.3.2",
    "source-map-loader": "^4.0.1",
    "style-loader": "^3.3.3",
    "vue-loader": "^17.3.1",
    "vue-template-compiler": "^2.7.15",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
  },
}
javascript vue.js webpack vuejs3 vue-router
1个回答
0
投票

您应该删除

webpack.config.js
并仅使用
vue.config.js

package.json

{
  "name": "marc-diff-checker",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "resolutions": {
    "coa": "2.0.2"
  },
  "dependencies": {
    "vue": "^3.2.16",
    "vue-router": "^4.0.12"
  },
  "devDependencies": {
    "@babel/eslint-parser": "^7.13.14",
    "@mdi/font": "^7.0.96",
    "@vue/cli-plugin-babel": "^5.0.8",
    "@vue/cli-plugin-eslint": "^5.0.8",
    "@vue/cli-plugin-router": "^5.0.8",
    "@vue/cli-service": "^5.0.8",
    "@vue/eslint-config-standard": "^8.0.1",
    "eslint": "^7.32.0",
    "eslint-plugin-html": "^6.0.0",
    "eslint-plugin-import": "^2.22.1",
    "eslint-plugin-node": "^11.0.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.1.0",
    "eslint-plugin-vue": "^9.6.0",
    "eslint-webpack-plugin": "^3.2.0",
    "postcss-import": "^12.0.1",
    "postcss-url": "^7.3.2",
    "sass": "1.32.8",
    "sass-loader": "^10.1.0",
    "stylelint": "^13.9.0",
    "stylelint-config-standard": "^20.0.0",
    "stylelint-scss": "^3.18.0",
    "stylelint-webpack-plugin": "^1.2.3"
  }
}

vue.config.js

'use strict';
const path = require('path');
const pk = require('./package.json');

module.exports =
{
  devServer:
  {
    port: 8080,
    client:
    {
      //logging: 'info',
      overlay:
      {
        errors: true,
        warnings: true,
        runtimeErrors: false,
      },
    }
  },
  lintOnSave: process.env.NODE_ENV !== 'production' ? 'error' : false,
  css:
  {
    sourceMap: process.env.NODE_ENV === 'development',
    /*
    loaderOptions:
    {
      postcss:
      {
        postcssOptions:
        {
          // without this Webpack complains that there is no PostCSS config inside the Vuetify/dist folder
          config: path.resolve(__dirname, '.postcssrc.js'),
        }
      },
    }
    */
  },
  productionSourceMap: true,
  configureWebpack: config =>
  {
    let parent;
    let dir = path.resolve(__dirname);
    const parsed = path.parse(dir);
    while (parsed.root !== dir)
    {
      dir = path.dirname(dir);
      parent = dir + (parsed.root !== dir ? path.sep : '') + 'node_modules';
      config.resolve.modules.push(parent);
      config.resolveLoader.modules.push(parent);
    }

    config.devtool = process.env.NODE_ENV === 'development' ? 'inline-source-map' : false; // other modes often break hot-reload and/or breakpoints
    if (!config.performance) config.performance = {};
    config.performance.hints = false;
  },
  chainWebpack: config =>
  {
    config.resolve.symlinks(false);
    config.resolve.alias.set('src', path.resolve(__dirname, 'src'));

    // !!!!!!! -- https://github.com/vuejs/vue-cli/issues/2978#issuecomment-441426094
    config.output.devtoolModuleFilenameTemplate(info =>
    {
      const resPath = path.normalize(info.resourcePath).split(path.sep).join('/');
      const isVue = resPath.match(/\.vue$/) && resPath.match(/^src/);
      //const isScript = info.query.match(/type=script/);
      //const hasModuleId = info.moduleId !== '';
      const isGenerated = info.allLoaders;

      const generated = `webpack-generated:///${resPath}?${info.hash}`;
      const vuesource = `vue-source:///${resPath}`;

      return isVue && !isGenerated ? vuesource : generated;
    });
    config.output.devtoolFallbackModuleFilenameTemplate('webpack:///[resource-path]?[hash]');

    // plugin options must be wrapped inside Array - otherwise error "non-callable @@iterator"
    if (process.env.NODE_ENV === 'development')
    {
      config.plugin('stylelintVue')
        .use(require('stylelint-webpack-plugin'),
          [
            {
              context: path.resolve(__dirname, 'src'),
              configFile: path.resolve(__dirname, 'stylelint.config.js'),
              files: '**/*.{vue,css,scss}',
              globbyOptions: { extension: false }, // otherwise "fastGlob" does not find anything if the folder contains brace(s)
              quiet: false,
              emitErrors: true
            }
          ]);
    }

    config.plugin('define')
      .tap(args =>
      {
        args[0]['process.env'].BUILD_TIME = JSON.stringify((new Date()).toISOString());
        args[0]['process.env'].VERSION = JSON.stringify(pk.version);
        return args;
      });
    return config;
  }
};

src/main.js

import { createApp, h } from 'vue';
import App from './App.vue';
import router from './router.js';

const myApp = createApp({
  name: 'RootApp',
  render()
  {
    return h(App);
  }
});

if (process.env.NODE_ENV === 'development')
{
  myApp.config.errorHandler = (err, vm, info) =>
  {
    // err: error trace
    // vm: component in which error occurred
    // info: Vue specific error information such as lifecycle hooks, events etc.
    console.error(vm.$options._componentTag + ': ' + info, err);
    events.$emit(SNACKBAR_FAILURE, vm.$options._componentTag + '\n' + info + '\n' + err.message + '\n' + err.stack);
  };

  window.onerror = function(message, source, lineno, colno, error)
  {
    alert('Error at ' + lineno + ':' + colno + ' in "' + source + '"\n' + message + '\n' + error);
  };
}

///myApp.config.globalProperties.$ajax = AJAX;
myApp.config.productionTip = false;
myApp.config.performance = false; // process.env.NODE_ENV !== 'production';
myApp.config.devtools = process.env.NODE_ENV !== 'production';

myApp.use(router);
myApp.mount('#app');

src/router.js

import { createRouter, createWebHistory } from 'vue-router';

import BadRoute from './views/BadRoute';
import Login from './views/auth/LoginPage';

const createHistory = createWebHistory;
const router = createRouter({
  scrollBehavior: () => ({
    left: 0,
    top: 0
  }),
  history: createHistory(process.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: Login,
      meta:
        {
          public: true
        }
    },
    // Always leave this as last one,
    // but you can also remove it
    {
      path: '/:catchAll(.*)*',
      component: BadRoute,
      meta:
        {
          title: 'NOT FOUND',
          public: true
        }
    }
  ],
});

router.afterEach((to, from) =>
{
  let title = to.meta.title;
  if (typeof title === 'function') title = title(to);
  if (title)
  {
    document.title = title;
  }
  else document.title = 'File History Diff';
});

// https://stackoverflow.com/a/63263736 - ignore NavigationDuplicated errors but keep other errors
const originalPush = router.push;
router.push = function push(location, onResolve, onReject)
{
  if (onResolve || onReject)
  {
    return originalPush.call(this, location, onResolve, onReject);
  }

  return originalPush.call(this, location).catch((err) =>
  {
    if (err && err.name === 'NavigationDuplicated')
    {
      return err;
    }

    return Promise.reject(err);
  });
};

export default router;

src/App.vue

<template>
  <v-app>
    <CustomHeader />
    <v-main>
      <router-view v-if="$route.meta.public || ($route.meta.admin ? $root.isAdmin : ($root.user || {}).uid)" :key="$root.refresh" v-slot="{Component}" class="pa-4">
        <transition name="fade" appear mode="out-in">
          <component :is="Component" />
        </transition>
      </router-view>
    </v-main>
    <CustomFooter />
    <v-overlay :value="$root.spin > 0" z-index="998">
      <v-progress-circular indeterminate size="64" />
    </v-overlay>
  </v-app>
</template>

<script>
import CustomHeader from './views/layout/MainHeader.vue';
import CustomFooter from './views/layout/MainFooter.vue';
import events, { USER_CHANGED } from './events.js';

export default
{
  name: 'App',
  components:
    {
      CustomHeader,
      CustomFooter,
    },
  created()
  {
    events.$on(USER_CHANGED, this.reload);
  },
  beforeUnmount()
  {
    events.$off(USER_CHANGED, this.reload);
  },
  methods:
  {
    reload()
    {
      this.$root.refresh++;
    },
  }
};
</script>

<style lang="scss">
  .fade-enter-active,
  .fade-leave-active
  {
    transition: all 0.15s cubic-bezier(0.55, 0, 0.1, 1);
  }

  .fade-enter,
  .fade-leave-active
  {
    opacity: 0;
    transform: translate(-2em, 0);
  }

  .must_login
  {
    filter: blur(7px);
  }
</style>
© www.soinside.com 2019 - 2024. All rights reserved.