javascript - Kan inte gå in i objekt definierat av rollup plugin-replace


I en Svelte-komponent försöker jag komma åt ett objekt som jag har ställt in i min rollup-konfigurationsfil. Min rollup.config.js-fil ser ut så här:

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

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

...

I min Svelte-komponent fungerar en enkel console.log(foo):

Men när jag försöker gå in i det där foo-objektet som console.log(foo.bar), får jag foo är inte definierad:

Svar #1

Bra fråga! Objektet foo förblir odefinierat så det ger rätt fel, och kan inte hitta foo för att ersätta med vad du än tänker ersätta det med.

Lösningen är att låta ersättningspluginen göra sitt jobb. Du kan komma åt din variabel så här i dina js- eller .svelte-filer

const { bar } = foo;

console.log(bar);

Observera: det gjordes en ändring i detta plugin, kolla här för detaljer. Om du planerar att använda miljövariabler med dotenv, överväg

import { config } from "dotenv";

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

och i din svelte-fil

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

Svar #2

Denna del av dokumentet förklarar ditt exakta problem.
https://github.com/rollup/plugins/tree/master/packages/replace#delimiters

Alternativet delimiters styr hur strängarna kommer att matchas. Med standardvärdet för delimiters som ['\b', '\b(?!\.)'] skulle det bara ersätta foo om det följer en ordgräns och följs av en ordgräns som inte är en punkt. Därför, med din rollup.config.js, skulle beteendet vara

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

Som du ser, tolkar inte replace-pluginet verkligen din kod utan utför istället bara enkel textersättning, inte alltför olik sök-och-erätt-funktionen i din IDE/editor. Gissa vad det skulle säga nedan?

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

För att sammanfatta, ditt tillfälliga lösning kan vara

  • foo['bar'],
  • const {{ bar }=foo,
  • undvik objektbyte och använd nycklar som __FOO_BAR__, __FOO_BAZ__, ...
  • skicka delimiters: ['\\b', '\\b'] för att tillåta punkter efter nyckeln.

(Men vid skrivandets stund verkar den sista ännu inte fungera på grund av en buggfix som väntar på att slås ihop).
https://github.com/rollup/plugins/pull/1088

Om du använder delimiters: ['',''] kräver det tidigare förbehållet en mycket högre grad av försiktighet. Även en strängliteral 'food' eller en HTML-malltagg <footer> kan ändras till nonsens som '{"bar":"Hello"}d' eller <{"bar":"Hello"}ter>. Så ge dina nycklar kloka namn eller använd några ovanliga avgränsare beroende på din användning, som den gamla versionen av plugin tidigare visade: delimiters: ['<@', '@>'].
https://github.com/rollup/rollup-plugin-replace

Ändå, eftersom denna typ av förbehandling är ganska rudimentär, behövs alltid försiktighet när man lägger till ersatta nycklar och när man använder dem.