emberjs / ember.js

Ember.js - A JavaScript framework for creating ambitious web applications
https://emberjs.com
MIT License
22.46k stars 4.21k forks source link

un-useful error message compiling template #19496

Closed BryanCrotaz closed 1 year ago

BryanCrotaz commented 3 years ago

Upgrading an old application to Ember 3.26.

<span {{action 'doSomething'}}>
</span>

Expected Compiles successfully or logs useful error message

Actual

Template Compiler Error (TemplateCompiler) in my-project/application/template.hbs

Cannot read property 'start' of undefined

The problem seems to be the action. Removing it fixes the error.

Obviously we shouldn't be doing this any more, and using a button with the on modifier instead. But the compiler error message does not help the developer find the problem and fix it.

Fix 1: Show location of error in .hbs file (line, column) Fix 2: Help the developer know what they've done wrong. Old tutorials will have developers writing code like this.

EDIT: Now happening with <div><button type="button"/></div>

pzuraq commented 3 years ago

Can you provide the full stack trace? This seems like a really strange error. There were some breaking changes to the private template transforms API, which some addons do make use of, so I wonder if it could be related to that.

jdurand commented 3 years ago

@pzuraq I've been going in circles trying to upgrade to ember 3.25 for a few weeks and (just a hunch) I just realized that commenting out <button> and <a> tags "solves" this issue :

// does-not-compile.hbs
<div>
  <button>{{yield}}</button>
</div>
// compiles-successfully.hbs
<div>
  <span>{{yield}}</span>
</div>

Here's a full stack trace :

(node:73190) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'start' of undefined
    at Source.spanFor (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:9071:26)
    at BlockContext.loc (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14161:26)
    at ElementNormalizer.attr (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14686:30)
    at /Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14558:24
    at Array.map (<anonymous>)
    at ElementNormalizer.ElementNode (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14557:10)
    at StatementNormalizer.normalize (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14405:52)
    at /Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14572:27
    at Array.map (<anonymous>)
    at ElementNormalizer.ElementNode (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14571:41)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:73190) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:73190) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:73190) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'start' of undefined
    at Source.spanFor (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:9071:26)
    at BlockContext.loc (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14161:26)
    at ElementNormalizer.attr (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14686:30)
    at /Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14558:24
    at Array.map (<anonymous>)
    at ElementNormalizer.ElementNode (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14557:10)
    at StatementNormalizer.normalize (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14405:52)
    at /Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14572:27
    at Array.map (<anonymous>)
    at ElementNormalizer.ElementNode (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14571:41)
(node:73190) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:73190) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'start' of undefined
    at Source.spanFor (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:9071:26)
    at BlockContext.loc (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14161:26)
    at ElementNormalizer.attr (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14686:30)
    at /Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14558:24
    at Array.map (<anonymous>)
    at ElementNormalizer.ElementNode (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14557:10)
    at StatementNormalizer.normalize (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14405:52)
    at /Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14572:27
    at Array.map (<anonymous>)
    at ElementNormalizer.ElementNode (/Users/jdurand/Code/libro/dashboard-web/node_modules/ember-source/dist/ember-template-compiler.js:14571:41)
(node:73190) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)
jdurand commented 3 years ago

In hopes it helps identify the root cause, I've been poking around and managed to get templates to compile by editing the spanFor function in /node_modules/ember-source/dist/ember-template-compiler.js :

_proto13.spanFor = function spanFor(_ref12) {
+  if (typeof _ref12 === 'undefined') {
+    return SourceSpan.forHbsLoc(this, {
+      start: { line: 0, column: 0 },
+      end: { line: 0, column: 0 }
+    });
+  }

  var start = _ref12.start,
      end = _ref12.end;
  return SourceSpan.forHbsLoc(this, {
    start: {
      line: start.line,
      column: start.column
    },
    end: {
      line: end.line,
      column: end.column
    }
  });
};

Unsurprisingly, now I get some runtime errors here and there :

TypeError: Cannot read property 'update' of undefined
    at isUpdatableRef (reference.js:138)
    at createReadOnlyRef (reference.js:112)
    at index.js:5128
    at Object.evaluate (runtime.js:2053)
    at AppendOpcodes.evaluate (runtime.js:1284)
    at LowLevelVM.evaluateSyscall (runtime.js:5179)
    at LowLevelVM.evaluateInner (runtime.js:5135)
    at LowLevelVM.evaluateOuter (runtime.js:5127)
    at VM.next (runtime.js:6259)
    at VM._execute (runtime.js:6243)
pzuraq commented 3 years ago

@jdurand can you provide a reproduction? We have templates just like this in tests, and they work as expected. Something else must be going on here to cause these errors, but I haven't been reproduce myself.

jdurand commented 3 years ago

@pzuraq here's a repo the reproduces the issue: https://github.com/jdurand/ember-source-issue-19496 I created a new ember v3.24.0 and just shoved all of my dependencies in there. I'll poke around this later.

pzuraq commented 3 years ago

@jdurand removing ember-hammertime as a dependency fixes the issue. It appears that ember-hammertime is adding a template AST transform. Template AST transforms are private API, which means that the API can change at any time and breakage can occur. Generally we try to avoid changes that will cause major issues, but sometimes it is unavoidable. In addition, it appears that ember-hammertime is not even using the builder API. This API would have insulated the plugin from the breakage, and is actually the way template transforms were meant to be built, so it's using the private API incorrectly in this case.

The solution will be to update ember-hammertime. I don't believe this is something we could make a better error message for, since it's creating an incorrect object and pushing it into the AST randomly, not via the builder API.

BryanCrotaz commented 3 years ago

Interesting. I was using ember hammer time via ember-gestures. I've removed ember-hammertime now as it's deprecated.

jdurand commented 3 years ago

Thanks @pzuraq. Linking these related issues for future reference :

jdurand commented 3 years ago

Just a little update in case someone else faces the same deprecation scenario. I was using ember-gestures for swipe actions. I was able to get rid of the ember-gestures dependency very easily with an ember-modifier:

// app/modifiers/on-swipe-right.js

import { modifier } from "ember-modifier";
import * as Hammer from 'hammerjs';

export default modifier((element, [fn]) => {
  const containerManager = new Hammer.Manager(element);
  const swipe = new Hammer.Swipe({
    direction: Hammer.DIRECTION_RIGHT,
    threshold: 10,
  });

  containerManager.add(swipe);
  containerManager.on('swiperight', fn, { passive: true });

  return () => {
    containerManager.destroy();
  }
});
<div
-  {{recognize-gesture "swipe"}}
-  {{on 'swiperight' (fn this.swipeRight @item)}}
+  {{on-swipe-right (fn this.swipeRight @item)}}
 >
  {{yield}}
</div>
sandstrom commented 1 year ago

I'm doing some issue gardening 🌱🌿 🌷 and came upon this issue. It seems outdated and likely no longer relevant.

By closing some old issues we reduce the list of open issues to a more manageable set.

Let me know if you think this is a mistake and that the issue should stay open.