rollup/rollup-plugin-json

Rolled up JSON assigned to the value "name" doesn't work in-browser

Psigio opened this issue · 2 comments

Hi,

I'm sure I'm doing something wrong, but I'm having trouble when rolling up a JSON value where it has a JSON key of "name":

{ "name" : { "key": "name-tag", "value": "Mr Jones" }, "address" : { "key": "address-tag", "value" : "1 Somewhere Street" } }

it rolls-up to the following:

var name = {"key":"name-tag","value":"Mr Jones"}; var address = {"key":"address-tag","value":"1 Somewhere Street"}; var fields = { name: name, address: address };

But it appears that name is defined in the global scope of Chrome, so the value is not overwritten, and the fields.name value is set to the globally scoped name.

I've created a simple project which reproduces the situation at https://github.com/Psigio/rollup-plugin-json-test

Am I missing some configuration option perhaps? One approach I tried was editing the list of reserved words in the https://github.com/rollup/rollup-pluginutils package to include "name" and this seemed to address the issue - the output was:
var address = {"key":"address-tag","value":"1 Somewhere Street"}; var fields = { address: address, "name": {"key":"name-tag","value":"Mr Jones"} };, but I wondered if there was a direct approach in rollup-plugin-json to achieve this?

Thanks!

Jon

The issue here is that you're writing to the global scope, rather than using the modules themselves. Let me walk you through the changes I made to your repro to get it to work as expected:

rollup.config.js

import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';

export default {
+    format: 'iife',
+    moduleName: 'myBundle',
    plugins: [
        nodeResolve({ jsnext: true, main: true, browser: true }),
        commonjs(),
        json()
    ]
};

By default, Rollup will create a JavaScript module. But what we actually want is something that works as a regular <script> tag – for that, we use the iife format or Immediately Invoked Function Expression.

An IIFE keeps all of your code inside a function block, meaning that your variables are local, and not competing with things like window.name:

(function () {
  // your code in here is safe
}());

In your case, a JavaScript module looks a lot like a regular script (because you didn't have any import or export declarations for the bundle as a whole), which was the source of the confusion. Future versions of Rollup will warn you if you forget to include a valid format option.

src/main.js

import preset_data from './data/data_index.js'
// Fields will have been imported via rollup

-function testFunction(){
+export function testFunction(){
    return "The Name value is " + JSON.stringify(preset_data.fields.name) + " and the address is " + JSON.stringify(preset_data.fields.address);
}
-// Reference the function to avoid it being removed as it appears unused
-console.log(testFunction());

If you want to use a function (or any other value) outside of a module, you have to export it. If you want to use it outside of the bundle, you have to export it from the entry module (src/main.js in your case). If something is exported, it won't be removed.

src/data/data_index.js

import { default as fields } from './data.json';

-export default preset_data = {
+export default {
    fields: fields
};

You don't need to give names to default exports.

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <title>Rollup-Plugin-Json-Test</title>

        <script src='dist/bundle.js' type='text/javascript'></script>
    </head>
    <body>
        <h1>Test</h1>
        <p id="target">...</p>
        <script>
-            document.getElementById("target").innerHTML=testFunction();
+            document.getElementById("target").innerHTML=myBundle.testFunction();
        </script>
    </body>
</html>

The last step is to reference the testFunction exported from the entry module. Because we gave the bundle a name – myBundle – in the config file, and created an IIFE, we can reference it as a global variable.

Hope this helps!

Many thanks for the explanation @Rich-Harris, I thought I must have been doing something wrong!