marked icon indicating copy to clipboard operation
marked copied to clipboard

Setting options interferes with other "require"-calls to marked.

Open nknapp opened this issue 8 years ago • 6 comments

In my NodeJS-project, marked is used by the main program and by a dependency. When the main-program calls setOptions, the same options are also applied to the instance that is used by the dependency, because both instances are the same object.

I think, a better way to apply default options, would be like the request-package is doing it. They create a new instance that is configured with the default options, so the original instance is untouched.

What I will try now, is to clear the cache before and after requiring marked, but that seems like a weak workaround.

nknapp avatar Jun 17 '17 10:06 nknapp

idk if this is viable for you, but you could avoid setting options with setOptions and instead pass options to marked as second argument.

I do agree with you that setOptions should return a new marked instance instead! But that is an API change.

Feder1co5oave avatar Dec 27 '17 02:12 Feder1co5oave

Again, I'm not too familiar with working directly with Marked; so, pardon the ignorance. Also, this sounds like the problem with Singletons (especially if they're configurable).

var marked1 = Marked().setOptions();
var marked2 = Marked().setOptions();

Is that not the way things work? Sounds like each package would want to create the instance, at which point you would access via something like:


var package = Package();

package.marked.setOptions();

In either case I'm not sure how much this is on Marked to correct. Will flag it for the 0.6.0 milestone; closing.

joshbruce avatar Dec 27 '17 12:12 joshbruce

A work around is to use

const marked = require('marked');
marked.setOptions(marked.getDefaults());

to make sure that defaults are set to the initial defaults.

UziTech avatar Dec 04 '19 21:12 UziTech

The proposed workaround can break those other marked "instances" which is also not good overall.

Andarist avatar Dec 04 '19 23:12 Andarist

True. You could also send options as a second parameter to marked to override the defaults just for that call.

const marked = require('marked');
marked(markdown, marked.getDefaults());

UziTech avatar Dec 05 '19 05:12 UziTech

I ran into this. As @Feder1co5oave said, the solution is to avoid using marked.setOptions({ renderer: renderer }) and instead pass options inline marked(md, { renderer: renderer }) - worked for me.

john-doherty avatar Jul 04 '21 20:07 john-doherty

I hate to rain on a parade, but this is a really clumsy issue. We did not realize this was happening (singleton instance in the background) and to make matters worse, our test pipeline turns over our server as it runs test cases. We had 3 extensions being added when the module was imported (which occurs on each test-reset) and found we had 1,926 extensions installed because marked has no way to reset existing options and it runs as a singleton.

Long gone are the days of polluting the global namespace with singletons like this. If changing the API is a problem, then maybe provide a method to obtain a separate instance with a new method on the API, for ex:

// Get a local instance...
const localMarked = marked.create({/* options here */);

// get some HTML...
const myHtml = localMarked.parse(myMd);

DLiblik avatar Oct 16 '22 20:10 DLiblik

...if it's helpful to others, you can clear block extensions (and other defaults - just change the property you are editing) by doing the following, but:

  • this accesses private code 💣
  • you will muck with any other marked instances 💥
if ((marked.defaults as any).extensions?.block?.length) {
  (marked.defaults as any).extensions.block = [];
}

...or, reset the defaults with:

const markedDefaults = {
  async: false,
  baseUrl: null,
  breaks: false,
  extensions: null,
  gfm: true,
  headerIds: true,
  headerPrefix: "",
  highlight: null,
  langPrefix: "language-",
  mangle: true,
  pedantic: false,
  renderer: null,
  sanitize: false,
  sanitizer: null,
  silent: false,
  smartLists: false,
  smartypants: false,
  tokenizer: null,
  walkTokens: null,
  xhtml: false,
};

(marked as any).defaults = {...markedDefaults};

DLiblik avatar Oct 16 '22 20:10 DLiblik

@DLiblik marked.getDefaults() will always return the default options object. You can reset marked with marked.setOptions(marked.getDefaults()).

This is something we have tried changing before with people complaining. It would be great if we can find a way to create an instance without breaking anyone who relys on the singleton.

UziTech avatar Oct 17 '22 03:10 UziTech

This is something we have tried changing before with people complaining. It would be great if we can find a way to create an instance without breaking anyone who relys on the singleton.

Wouldn't a create() method as suggested by @DLiblik above work?

rfgamaral avatar Apr 18 '23 09:04 rfgamaral

@rfgamaral sure. If you want to create a PR and add tests to make sure it is working we could add a create method

UziTech avatar Apr 18 '23 20:04 UziTech

fyi we have another issue related to this where I proposed some approaches and also shared a simple workaround that works for my use case. It may be helpful for those struggling in some way, or for those considering making a contribution.

icebaker avatar May 31 '23 13:05 icebaker