jashkenas / underscore

JavaScript's utility _ belt
https://underscorejs.org
MIT License
27.33k stars 5.53k forks source link

ESM: template() can cause a `_.escape is not a function` error #2863

Closed ocean90 closed 4 years ago

ocean90 commented 4 years ago

I'm using underscore@1.10.2 and tried to use the ESM version like this.

import { template } from 'underscore/modules/index';

const t = template( '<b><%- value %></b>' );
console.log( t( { value: '<b>yolo</b>' } ) );

Unfortunately this is causing a Uncaught TypeError: _.escape is not a function error. The error doesn't happen if the function doesn't need to escape something. Am I'm doing something wrong here? It's unclear to me why it tries to access the underscore global. Webpack is used to build the app.

The same happens with the latest commit, using underscore@github:jashkenas/underscore#977d4be74fe76227f5e9f3af9d640b46ab5b50dd.

jgonggrijp commented 4 years ago

@ocean90 Thanks for reaching out. This is expected behavior for modular usage, you can enable HTML escaping as follows:

import { template, escape, mixin } from 'underscore/modules/index';

mixin({ escape });

const t = template( '<b><%- value %></b>' );
console.log( t( { value: '<b>yolo</b>' } ) );

Your own template code might also reference other Underscore functions through the _ namespace handle, for example _.each. Those functions also need to be enabled using mixin like above.

I'm currently writing an article about modular Underscore in which I explain this in more detail.

ocean90 commented 4 years ago

Thanks or the quick answer, @jgonggrijp. With the mixin() part it's working fine now. 🙌

jgonggrijp commented 4 years ago

Leaving this open as a temporary documentation until the article has been published.

jgonggrijp commented 4 years ago

The article was published in the meanwhile. The relevant section is here.

From Underscore 1.11 onwards, the above code snippet still works, but I recommend a slightly different way of importing:

import template from 'underscore/modules/template.js';
import escape from 'underscore/modules/escape.js';
import mixin from 'underscore/modules/mixin.js';

mixin({ escape });

const t = template( '<b><%- value %></b>' );
console.log( t( { value: '<b>yolo</b>' } ) );

I also recommend isolating the modular imports from the code that actually uses Underscore through a custom build.