How to import a different bundle for server and client using Rollup in Sapper?

1.2k Views Asked by At

I'm creating a tool which launches a server and fetches content from the server and displays it in the browser. I'm trying to integrate it with frontend frameworks. One of those frameworks is Sapper/Svelte. The problem is that my bundle contains imports to built-in modules which are not needed by the browser, and also not resolved by the browser, which in turn throws an error.

I think what I need to do is make my tool isomorphic and split my tool it into two bundles. One for the server (server.js), and one for the browser (client.js) which doesn't contain the imports to built-in modules. I have a good idea of how I can split the code, using code splitting in Rollup, but what I don't know is how I tell Sapper to use server.js for the server and client.js for the client.

How can I bundle my module so when it's consumed by other applications it knows which one to use for the server and which one to use for the browser? Is this something I can do in my module or do I have to also configure this in the framework it's being used in?

1

There are 1 best solutions below

0
limitlessloop On

I discovered that @rollup/plugin-node-resolve has a flag to instruct Rollup to use an alternative bundle specified in the browser property in the module's package.json.

As Sapper is configured to create a bundle for both the client and server it has this flag already in it's rollup.config.js.

Sapper

// rollup.config.js

export default {
    client: {
        // ...
        plugins: [
            // ...
            resolve({
                browser: true, // <-- flag
                dedupe: [ 'svelte' ],
                exclude: [ 'node_modules/**' ]
            })
            // ...

No changes needed here.

Your NPM Module

You need to create two bundles. One for the server and one for the browser. I felt it was easier to create two different entry points in Rollup for this. It might be possible to use the same entry point and use conditional logic to output a different bundle (something I'm not familiar with).

// rollup.config.js

export default [
    {
        input: 'src/server.js',
        output: {
            file: 'dist/server.js',
            format: 'cjs'
        }
    },
    {
        input: 'src/browser.js',
        output: {
            file: 'dist/browser.js',
            format: 'cjs'
        }
    }
];

Now we add the path to the browser specific bundle in package.json.

// package.json

{
  "main": "dist/server.js"
  // ...
  "browser": "dist/browser.js"
}

Setting this up means that when Sapper starts it will use a different bundle for the server and the client. When you create the separate bundles you need to structure them so that they work independently of each other. In my case, I isolated all server functionality to the server-specific bundle and excluded all dependencies like http, fs and path from the browser-specific bundle.