Search code examples
sveltees6-modulescommonjsrollup

Import commonjs library in svelte/rollup app


I am developing a svelte-based electron app to learn the framework (I have no previous experience with svelte or rollup).

When importing the library modbus-serial into the App.svelte component of a new app (import ModbusRTU from "modbus-serial" or const ModbusRTU = require("modbus-serial")), I keep getting the following error on the console:

Uncaught ReferenceError: require is not defined

What am I missing?

Note: I am aware that the library is implemented for nodejs. I am in fact trying to port to svelte, for learning purposes, an IoT app previously built with electron + react and electron + vue. With react and vue I had no problems importing the library.

Below my rollup.config.js:

import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';
import css from 'rollup-plugin-css-only';

const production = !process.env.ROLLUP_WATCH;

function serve() {
    let server;

    function toExit() {
        if (server) server.kill(0);
    }

    return {
        writeBundle() {
            if (server) return;
            server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
                stdio: ['ignore', 'inherit', 'inherit'],
                shell: true
            });

            process.on('SIGTERM', toExit);
            process.on('exit', toExit);
        }
    };
}

export default {
    input: 'src/main.ts',
    output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'public/build/bundle.js'
    },
    plugins: [
        svelte({
            preprocess: sveltePreprocess({ sourceMap: !production }),
            compilerOptions: {
                // enable run-time checks when not in production
                dev: !production
            }
        }),
        // we'll extract any component CSS out into
        // a separate file - better for performance
        css({ output: 'bundle.css' }),

        // If you have external dependencies installed from
        // npm, you'll most likely need these plugins. In
        // some cases you'll need additional configuration -
        // consult the documentation for details:
        // https://github.com/rollup/plugins/tree/master/packages/commonjs
        resolve({
            browser: true,
            dedupe: ['svelte']
        }),
        commonjs(),
        typescript({
            sourceMap: !production,
            inlineSources: !production
        }),

        // In dev mode, call `npm run start` once
        // the bundle has been generated
        !production && serve(),

        // Watch the `public` directory and refresh the
        // browser on changes when not in production
        !production && livereload('public'),

        // If we're building for production (npm run build
        // instead of npm run dev), minify
        production && terser()
    ],
    watch: {
        clearScreen: false
    }
};

Solution

  • This problem may be caused by the mixing of commonjs require & esm import statements in the same project. Adding transformMixedEsModules to the config of @rollup/plugin-commonjs should help somewhat resolve the issue:

    // rollup.config.js
    // ...
    commonjs({
      transformMixedEsModules: true,
    }),
    // ...
    

    Do note however, that I've personally ran into tonnes of issues bringing modules targeting node specifically to the web. This is because require is by design dynamic, thus if used in ways that can't be statically analyzed, you may need to explore more hacky workarounds, listed here. Other than that, shims, shams, & polyfills of node modules aren't always 100% implemented either.

    However, you're in luck! Since you're targetting electron, you may look into importing (require-ing) these modules via the main process & using IPC to communicate with it instead, see here for more info.