4

我有一个 Vue.js 项目,它直到几分钟前才正常工作。npm run build停止工作时,我正在尝试添加一个新的小功能,Syntax Error您会在下面看到。我花了一些时间阅读它,但在我看来,Unexpected token除了它在 App.vue 中之外,没有任何关于它实际在哪里的线索。

我怀疑我可能最终可以通过取出代码来让它工作,直到我弄清楚它正在窒息,但是处理这些错误消息的首选方法是什么?它们似乎没有帮助,每次我得到 a 时都提取代码Syntax Error比立即知道错误在哪里要慢得多。

| building for production...
Starting to optimize CSS...
Processing css/app.b78de1b1e52d045850f3f8ef25eab789.css...
Processed css/app.b78de1b1e52d045850f3f8ef25eab789.css, before: 2077, after: 2009, ratio: 96.73%
Hash: 463db738399a4df0bc89
Version: webpack 2.6.1
Time: 7211ms
                                           Asset       Size  Chunks             Chunk Names
                  js/app.46d986e313fa2c015cd0.js    5.62 kB       0  [emitted]  app
               js/vendor.bf7e840e23d2fcdbebe0.js     141 kB       1  [emitted]  vendor
             js/manifest.c323c0be7462a1c8da87.js    1.51 kB       2  [emitted]  manifest
    css/app.b78de1b1e52d045850f3f8ef25eab789.css    2.01 kB       0  [emitted]  app
              js/app.46d986e313fa2c015cd0.js.map      26 kB       0  [emitted]  app
css/app.b78de1b1e52d045850f3f8ef25eab789.css.map    4.13 kB       0  [emitted]  app
           js/vendor.bf7e840e23d2fcdbebe0.js.map     974 kB       1  [emitted]  vendor
         js/manifest.c323c0be7462a1c8da87.js.map    14.6 kB       2  [emitted]  manifest
                        ..\..\templates\app.html  598 bytes          [emitted]

ERROR in ./~/vue-loader/lib/template-compiler?{"id":"data-v-59c95520"}!./~/vue-loader/lib/selector.js?type=template&index=0!./src/App.vue
Module build failed: SyntaxError: Unexpected token (72:13)
    at Parser.pp$4.raise (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:2231:15)
    at Parser.pp.unexpected (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:613:10)
    at Parser.pp.expect (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:607:28)
    at Parser.parseObj (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:3871:16)
    at Parser.pp$3.parseExprAtom (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1815:19)
    at Parser.parseExprAtom (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:3800:24)
    at Parser.pp$3.parseExprSubscripts (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1725:21)
    at Parser.pp$3.parseMaybeUnary (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1702:19)
    at Parser.pp$3.parseExprOps (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1647:21)
    at Parser.pp$3.parseMaybeConditional (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1630:21)
    at Parser.pp$3.parseMaybeAssign (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1607:21)
    at Parser.pp$3.parsePropertyValue (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:2008:89)
    at Parser.parseObj (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:3895:14)
    at Parser.pp$3.parseExprAtom (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1815:19)
    at Parser.parseExprAtom (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:3800:24)
    at Parser.pp$3.parseExprSubscripts (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1725:21)
    at Parser.pp$3.parseMaybeUnary (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1702:19)
    at Parser.pp$3.parseExprOps (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1647:21)
    at Parser.pp$3.parseMaybeConditional (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1630:21)
    at Parser.pp$3.parseMaybeAssign (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1607:21)
    at Parser.pp$3.parseExprList (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:2175:22)
    at Parser.pp$3.parseSubscripts (C:\path_to_project\client\node_modules\vue-template-es2015-compiler\buble.js:1751:35)
 @ ./src/App.vue 8:2-170
 @ ./src/main.js

这是 App.vue:

<template>
  <div id="app">
    <div id="toolbar" v-on-clickaway="disableSongToolbar">
      <div id="toolbar__left">
        <a class="ui-text toolbar__option" href="/">Rhymecraft</a>
        <div class="ui-text toolbar__option"
             :class="{ toolbar__option_active: songToolbarActive }"
             @click="toggleSongToolbarDropdown()">
          Song
        </div>
        <div class="ui-text toolbar__option">Line</div>
        <div class="ui-text toolbar__option">Help</div>
      </div>
      <div id="toolbar__right">
        <a class="ui-text toolbar__option" href="/logout">Log out</a>
      </div>
    </div>
    <div id="toolbar-dropdowns">
      <div id="toolbar-dropdowns__song" v-show="songToolbarActive">
        <div class="ui-text toolbar__option toolbar-dropdown-option toolbar-dropdown-not-last-option"
             @click="createNewSong">Create new song</div>
        <div class="ui-text toolbar__option toolbar-dropdown-option"
            @click="displayListOfUsersSongs">Load song</div>
        <div class="ui-text toolbar__option toolbar-dropdown-option"
             v-if="song.hasOwnProperty('id')"
            @click="displayConfirmDeleteSong = true">Delete current song</div>
      </div>
    </div>
    <div id="modals" :class="{ modals-active: modalActive }">
      <div id="song-loader" v-show="displaySongLoader">
        <div id="song-loader-header" class="ui-text">Load Song</div>
        <div class="ui-text song-loader__item song-loader__selectable-item" v-for="song in songs" @click="loadSong(song.id)">{{ song.name }}</div>
        <div class="ui-text song-loader__item" v-if="songs.length === 0 || !songs[0].hasOwnProperty('id')">You do not have any songs.</div>
        <div id="song-loader__cancel" class="ui-text" @click="displaySongLoader = false">Cancel</div>
      </div>
      <div id="confirm-delete-song" v-show="displayConfirmDeleteSong">
        <div id="confirm-delete-song__header" class="ui-text">Delete Song</div>
        <div id="confirm-delete-song__cancel" class="ui-text" @click="displayConfirmDeleteSong = false">Cancel</div>
        <div id="confirm-delete-song__spacer"></div>
        <div id="confirm-delete-song__confirm" class="ui-text" @click="deleteCurrentSong">Confirm</div>
      </div>
    </div>
    <div id="song-area">
      <div id="song">
        <div v-for="line in song.lines" class="song-line">
          <div v-for="spanOfTime in line.spansOfTime"
               class="ui-text span-of-time span-of-time--4"
               :id="spanOfTime.id"
               @click="currentlySelectedSpanOfTime = spanOfTime.id; console.log(spanOfTime.id)">&nbsp;</div>
        </div>
      </div>
    </div>
    <router-view></router-view>
  </div>
</template>

<script>
import { mixin as clickaway } from 'vue-clickaway'

export default {
  name: 'app',
  mixins: [ clickaway ],
  data: function () {
    return {
      songToolbarActive: false,
      displaySongLoader: false,
      song: [],
      songs: [],
      displayConfirmDeleteSong: false,
      currentlySelectedSpanOfTime: -1
    }
  },
  computed: {
    modalActive: function () {
      if (this.displaySongLoader) {
        return true
      }
    }
  },
  methods: {
    toggleSongToolbarDropdown: function () {
      this.songToolbarActive = !this.songToolbarActive
    },
    disableSongToolbar: function () {
      if (this.songToolbarActive) {
        this.songToolbarActive = false
      }
    },
    createNewSong: function () {
      this.$http.post('/song/create').then(response => {
        this.song = response.data.song
      }, response => {
        // error callback
      })
    },
    displayListOfUsersSongs: function () {
      this.$http.get('/songs').then(response => {
        this.songs = response.data.songs
        this.displaySongLoader = true
      }, response => {
        // error callback
      })
    },
    loadSong: function (songId) {
      this.displaySongLoader = false
      this.$http.get('/song/' + songId).then(response => {
        this.song = response.data.song
      }, response => {
        this.song = []
      })
    },
    deleteCurrentSong: function () {
      this.displayConfirmDeleteSong = false
      this.$http.post('/song/' + this.song.id + '/delete').then(response => {
        this.song = []
      }, response => {
      })
    }
  }
}
</script>

<style>
html, body {
  height: 100%;
}
div#modals {
  position: absolute;
  text-align: center;
  width: 100%;
  height: 100%;
  display: flex;
}
div.modals-active {
  z-index: 1;
}
div#song-loader {
  width: 300px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: auto;
  border: 1px solid rgb(85, 85, 85);
}
div#song-loader-header {
  padding: 5px 0px;
  background-color:rgb(60,63,65);
}
div.song-loader__item {
  background-color: beige;
  padding: 10px;
  color: rgb(60, 60, 60);
}
div.song-loader__selectable-item:hover {
  background-color: rgb(230, 230, 190);
}
div#song-loader__cancel {
  padding: 5px 0px;
}
div#song-area {
  height: 100%;
}
div#song {
  width: 608px;
  height: 30px;
  margin: auto;
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}
div.span-of-time {
  background-color: white;
  min-height: 29px;
  display: inline-block;
  border-right: 1px solid rgb(200,200,200);
}
div.span-of-time--4 {
  width: 37px;
}
div#app {
  height: 100%
}
div#toolbar {
  border-bottom: 1px solid #282828;
  box-shadow: 0px 1px 1px rgb(85,85,85);
}
div#toolbar__left {
  display: inline-block;
}
div#toolbar__right {
  display: inline-block;
  float: right;
}
.ui-text {
  color: #BBBBBB;
  font-size: 13px;
  text-decoration: none;
  font-family: 'Martel Sans', sans-serif;
  cursor: default;

  /* noselect */
    -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome and Opera */
}
div#toolbar-dropdowns {
  position: absolute;
  z-index: 2;
}
.toolbar__option {
  display: inline-block;
  height: 25px;
  padding: 2px 5px 0px 5px;
}
.toolbar__option:hover {
  color: rgb(225,225,225);
  cursor: pointer;
}
div.toolbar__option_active {
  background-color: rgb(75,110,175);
}
div#toolbar-dropdowns__song {
  margin-left: 86px;
  width: 190px;
  border: 1px solid dimgray;
}
div.toolbar-dropdown-not-last-option {
  border-bottom: 1px solid dimgray;
}
div.toolbar-dropdown-option {
  cursor: default;
  width: 181px;
  display: inline-block;
  font-size: 12px;
}
div.toolbar-dropdown-option:hover {
  background-color: rgb(75,110,175);
}
.noselect {
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome and Opera */
}
</style>

更新:我通过删除代码直到npm run build再次工作才发现错误。问题是我创建了一个名称中带有破折号的条件类,但没有用单引号将类名括起来。所以不是:class="{ 'modals-active': modalActive }"我有:class="{ modals-active: modalActive }".

但是,我问这个问题并不是为了解决这个特定问题,而是想知道是否有任何方法可以使用这些错误消息来更快地解决问题。实际问题出在.vue模板文件的第 29 行,但错误消息似乎表明错误在第 72 行。

4

1 回答 1

0

我有一个类似的问题,原来是这个小代码片段:

item = {
  ...item,
  ...this.files[file]
};

我最好的猜测是 webpack 不喜欢 ES2018 中引入的对象扩展运算符。

于 2021-02-19T22:34:08.250 回答