DEV Community

DougAnderson444
DougAnderson444

Posted on • Updated on

Isomorphic + Rollup + Package.json

Isomorphic + Rollup + Package.json

It took me a while to piece this all together, so I'm mainly posting these notes here for myself as I go along.

We want same code for nodejs and the browser, so in package.json we set:

// package.json
...
"main": "dist/index.js",
"browser": "lib/index.browser.js"
...
Enter fullscreen mode Exit fullscreen mode

But maybe we want both ES and UMD modules available to the browser user, so we break browser out:

// package.json -  browser expanded
  "main": "dist/index.js",
  "module": "dist/index.esm.js",
  "browser":{ 
    "dist/index.js": "dist/index.browser.js",
    "dist/index.esm.js": "dist/index.browser.esm.js"
  },
Enter fullscreen mode Exit fullscreen mode

Now, depending on how the user imports the package, will determine what file they get. If they use index.js from nodejs the user will get dist/index.js but if they use index.js from the browser they will get dist/index.browser.js!

Make the files

We can use Rollupjs to make these files

// rollup.config.js
...
import pkg from './package.json'
...
export default [
    // browser-friendly builds
    {
        input: 'src/main.js',
        output: [{
            name: 'myPkgName',
            file: pkg.browser['dist/index.js'], // from package.json
            format: 'umd'
        },
        {
            file: pkg.browser['dist/index.esm.js'], // from package.json
            format: 'es'
        }]
        plugins: [
            resolve(), // so Rollup can bundle modules
            babel({
                exclude: ['node_modules/**']
            }),
            commonjs(), // so Rollup can convert to ES module
        ]
    },

    // CommonJS (for Node) and ES module (for bundlers) build.
    // (We could have three entries in the configuration array
    // instead of two, but it's quicker to generate multiple
    // builds from a single configuration where possible, using
    // an array for the `output` option, where we can specify 
    // `file` and `format` for each target)
    {
        input: 'src/main.js',
        output: [
            { file: pkg.main, format: 'cjs' }, // from package.json
            { file: pkg.module, format: 'es' } // from package.json
        ],
        plugins: [
            babel({
                exclude: ['node_modules/**']
            })
        ]
    }
];
Enter fullscreen mode Exit fullscreen mode

Use the ES Module

Now that you have an ES module, you can import it into your code

import NamedExport from 'myCoolModule'
Enter fullscreen mode Exit fullscreen mode

Bundle your code (again) with Rollup in the same way, perhaps using a front end framework like Svelte.

// bundled output from a framework, like Svelte
build/bundle.js
Enter fullscreen mode Exit fullscreen mode

Now that you have all these modules, and they are bundled into the code, they can also be used for cool things like code-splitting and dynamic imports.

// index.html
<!-- This standard way only works if the browser 
is modern and supports dynamic imports -->
<script defer type="module" src='/build/main.js'></script>      
Enter fullscreen mode Exit fullscreen mode

Dynamic Import an ES module in any browser

Use dimport:

<!-- https://www.npmjs.com/package/dimport -->
<script defer type="module" src="https://unpkg.com/dimport?module"
data-main="/build/main.js"></script>

<script defer type="nomodule" src="https://unpkg.com/dimport/nomodule" 
data-main="/build/main.js"></script> 

Enter fullscreen mode Exit fullscreen mode

Refs:
dimport
Dynamic Imports
Svelte Code Splitting
Svelte Code Splitting without Sapper
Code Splitting Routify
Target based Dependency Transpiling
Package.json Browsr Swithcing
Pkg.json Browser Tests
Rollup Config: Multi-inputs
Rollup Config: babel

Top comments (0)