Can't go into object defined by rollup plugin-replace

Viewed 457

In a Svelte component, I'm trying to access an object I set up in my rollup config file. My rollup.config.js file looks like this:

import replace from '@rollup/plugin-replace';

...
export default {
...
    replace({
        foo: JSON.stringify({ bar: 'Hello' }),
    }),

...

In my Svelte component, a simple console.log(foo) works:

foo

But when I try to go into that foo object like console.log(foo.bar), I get foo is not defined:

fooUndefined

2 Answers

Good question! The object foo remains undefined so it is throwing the right error, and is unable to find foo to replace with whatever you are going to replace it with.

The solution is having the replace plugin do its job. You may access your variable like this in your js or your .svelte files


const { bar } = foo;

console.log(bar);

Note: there was a change made to this plugin check here for details. if you are planning to use environment variables using dotenv consider

import { config } from "dotenv";

...
replace({
      values: {
        foo: JSON.stringify({ bar: "Hello", ...config().parsed }),
      },
    }),
...

and in your svelte file

  const { bar, ...rest } = foo;
  console.log("bar=>", bar);
  console.log("env=>", rest);

This section of the document explains your exact problem.
https://github.com/rollup/plugins/tree/master/packages/replace#delimiters

The delimiters option controls how the strings will be matched. With the default delimiters being ['\b', '\b(?!\.)'], it would only replace foo if it follows a word boundary and is followed by a word boundary that is not a dot. Hence with your rollup.config.js the behaviour would be

console.log(foo)
// becomes
console.log({"bar":"Hello"})

console.log(foo.bar)
// is not replaced by the plugin as `foo` IS followed by a dot

console.log(foo['bar'])
console.log(foo .bar) // space after `foo`
// both satisfy the delimiter check again and print: Hello
// (horrible coding style in the latter but to illustrate how it works)

const { bar } = foo
// also satisfy the delimiter check hence
console.log(bar) // prints: Hello

As you see, the replace plugin doesn't really parse your code but instead only preforms simple text replacement not too different from the search-and-replace feature of your IDE/editor. Gauss what would it say below?

console.log('foo')
// Guess what?
// ...
// ...
// printed: {"bar":"Hello"}
// as if it were
console.log('{"bar":"Hello"}')

To conclude, your workaround might be

  • foo['bar'],
  • const { bar } = foo,
  • avoid object replacement and use keys like __FOO_BAR__, __FOO_BAZ__, ...
  • pass delimiters: ['\\b', '\\b'] to allow dots following the key.

(However at the moment of writing, the last one doesn't seem to work yet due to a bugfix waiting to be merged).
https://github.com/rollup/plugins/pull/1088

If you use delimiters: ['', ''] the earlier caveat requires much higher level of caution. Even a string literal 'food' or a HTML template tag <footer> might be changed to gibberish like '{"bar":"Hello"}d' or <{"bar":"Hello"}ter>. So name your keys wisely or use some unusual delimiters depending on your usage, like what the old version of the plugin once demonstrated: delimiters: ['<@', '@>'].
https://github.com/rollup/rollup-plugin-replace

Nevertheless since these kind of preprocessing is pretty rudimentary, care is always needed when adding replaced keys and when using them.

Related