FredKSchott / rollup-plugin-polyfill-node

A modern Node.js polyfill for your Rollup bundle.
Other
176 stars 55 forks source link

'default' is not exported by ... #38

Closed theurgi closed 2 years ago

theurgi commented 2 years ago

In a SvelteKit project (using Vite) I was getting errors derived from dependencies of a package I'm using referencing node globals. Here's my original issue for reference: https://github.com/blocknative/onboard/issues/762.

After much searching I found this package and used it as shown in https://github.com/FredKSchott/rollup-plugin-polyfill-node/issues/14#issue-851995485.

This fixed everything on the dev server, no more ReferenceError: Buffer is not defined etc.

But then when I went to build I ran into another issue that I do not experience without rollup-plugin-polyfill-node...

'default' is not exported by node_modules/js-sha3/src/sha3.js, imported by node_modules/@ethersproject/keccak256/lib.esm/index.js

I can add node_modules/js-sha3/src/sha3.js to the exclude array and it remedies the issue for that particular module but then the next attempted default import fails the build.

I tried @rollup/plugin-node-resolve and @rollup/plugin-commonjs to no avail. Is there another rollup plugin I need?

Here are the relevant parts of my config:

// svelte.config.js
import nodePolyfills from 'rollup-plugin-polyfill-node'

const config = {
  kit: {
    vite: {
      plugins: [
        nodePolyfills({
          include: [
            '*.js',
           'node_modules/**/*.js',
            new RegExp('node_modules/.vite/.*js')
          ],
          // ↓ Not sure if this line is necessary, seems to work without it
          exclude: ['node_modules/polyfill-nodeglobal.js']
        })
      ],
      resolve: {
        alias: {
          // ↓ see https://github.com/vitejs/vite/issues/6085
          '@ensdomains/address-encoder': '@ensdomains/address-encoder/lib/index.umd.js'
        }
      }
    }
  }
}

export default config
theurgi commented 2 years ago

Update

I added all files to exclude that do not export 'default' and the build completed. However when I preview the build, nothing loads and Uncaught ReferenceError: require is not defined is logged to the console.

How can this run and work as expected on the dev server but not build?

theurgi commented 2 years ago

After trying 100 different configurations like a dumb monkey, I stumbled upon one that finally worked both on the dev server and in the build.

My solution: https://github.com/blocknative/onboard/issues/762#issuecomment-997246672

syffs commented 2 years ago

@theurgi I'm having the same issue, but I'm using rollup directly (not vite). Tried to understand the takeaway from your solution, but it doesn't work and I don't get how it would work: You're simply

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 nodePolyfills from 'rollup-plugin-polyfill-node'
import path from 'path'

const projectRootDir = path.resolve(__dirname)
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: !production,
        format: 'iife',
        name: 'SomeSdk',
        file: `public/build/some-sdk${production ? '.min' : ''}.js`,
    },
    plugins: [
        svelte({
            compilerOptions: {
                dev: !production,
                cssHash: ({hash, css}) => `h-${hash(css)}`,
            },
            preprocess: sveltePreprocess({
                sourceMap: !production,
                postcss: {
                    plugins: [
                        require("autoprefixer")(),
                        require("tailwindcss")(),
                        ...(production ? [require("cssnano")()] : []),
                    ],

                },
            }),
            emitCss: false,
        }),

                // ↓ had this
        // nodePolyfills(),
                // ↓ updated to this
                ...(process.env.NODE_ENV === 'development' ? [nodePolyfills({ include: ['node_modules/**/*.js'] })] : [nodePolyfills()]),

        resolve({
            browser: true,
            dedupe: ['svelte']
        }),
        commonjs({
                        // ↓ added this
            transformMixedEsModules: true,
        }),
        typescript({
            sourceMap: !production,
            inlineSources: !production
        }),

        !production && serve(),
        !production && livereload('public'),
        production && terser()
    ],
    watch: {
        clearScreen: false
    }
}

The error I'm getting is:

[!] Error: 'default' is not exported by node_modules/js-sha3/src/sha3.js, imported by node_modules/@ethersproject/keccak256/lib.esm/index.js
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
node_modules/@ethersproject/keccak256/lib.esm/index.js (2:7)
1: "use strict";
2: import sha3 from "js-sha3";

So in short, we'd need import sha3 from "js-sha3" translated to import * as sha3 from "js-sha3". Not sure how to achieve that.

any insight ?

theurgi commented 2 years ago

I'm sorry, I don't have any certainty about what might be causing this issue. As I was trying many different configurations I do recall getting the specific error you're running into.

I don't know exactly what Vite does behind the scenes with Rollup, or in what order it does it—the cost of abstraction.

Have you tried various orderings for the nodePolyfills, resolve, and commonjs plugins?

syffs commented 2 years ago

@theurgi I see, thanks for sharing !

I got fed up by this issue and ended up simply using ethers esm build as a workaround:

import {ethers} from 'ethers/dist/ethers.esm'
imsys commented 2 years ago

I finally understand what's going on, this explain quite well: https://github.com/evanw/esbuild/issues/1719#issuecomment-953470495 and in this link too: https://github.com/rollup/plugins/tree/master/packages/commonjs#defaultismoduleexports Hopefully I will soon get it working.

imsys commented 2 years ago

My case is explained in this issue: https://github.com/blocknative/onboard/issues/794 And I have a demonstration example at: https://github.com/imsys/sveltekit-onboard-test I give all the credits to @theurgi for getting most of the working configuration. For me, the production builds fine, but the development I get a problem. onboard requires the cjs package @gnosis.pm/safe-apps-sdk.

gnosis contains Object.defineProperty(exports, "__esModule", { value: true }); And being so, @rollup/plugin-commonjs has the setting of defaultIsModuleExports to auto, and this will make gnosis import return an object of { default: value } and I would like to set defaultIsModuleExports to false. But as @rollup/plugin-commonjs is included in rollup-plugin-polyfill-node, it seems that I need to pass the configurations there and I can't. https://github.com/FredKSchott/rollup-plugin-polyfill-node/blob/3489809368a97408be824f743d5bde388f0abd73/scripts/build-polyfills.js#L29

Maybe if I could pass the config like:

nodePolyfills({
    commonjsOptions: {
        defaultIsModuleExports : false
    }
})

I think in this way I would be able to get it working.

imsys commented 2 years ago

Edit: that invocation of @rollup/plugin-commonjs seems to be to polyfill just a few specific files,.. so,.. my mistake.

FredKSchott commented 2 years ago

Fixed by https://github.com/FredKSchott/rollup-plugin-polyfill-node/pull/42

coolcorexix commented 1 year ago

I still encounter this problem while using Vite, after fixing the problem on buffer I get thrown other errors where vite get import * as from and import from incorrectly. The way I overcome this problem is not to use this plugin at all and instead inject only the nodejs deps I need direcly.

First install buffer deps:

npm install -D buffer

Then. Two way of doing this:

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

//  vite.config.ts
export default defineConfig({
...
  build: {
    rollupOptions: {
      plugins: [inject({ Buffer: ['Buffer', 'buffer'] })],
    },
  },
...
})

or this

import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill'

export default defineConfig({
...
 optimizeDeps: {
    esbuildOptions: {
      // Node.js global to browser globalThis
      define: {
        global: 'globalThis'
      },
      // Enable esbuild polyfill plugins
      plugins: [
        NodeGlobalsPolyfillPlugin({
          process: true,
          buffer: true
        }),
      ]
    },
  },
...
})

I prefer first solution for semantic reason, because this is not an ‘optimize’ at all, without this config the whole build will just break. But sadly, this solution does not work with another project.

UPDATE: another way I found out is to use aliases, like this:

npm install -D rollup-plugin-node-polyfills
// vite.config.ts
resolve: {
    alias: {
  ...
      buffer: 'rollup-plugin-node-polyfills/polyfills/buffer-es6',
      process: 'rollup-plugin-node-polyfills/polyfills/process-es6'
    }
  },

And a notice that this will only suitable for the case you need a few built in deps. In case there is a lot of deps needed, it is better if this plugin can handle that. @FredKSchott can you please take a look at the case of using this plugin in vitejs, I really want to know the root cause of this plugin breaking in this case. Just let me know if you want to triage, have a minimla reproduce repo or a PR. I am more than happy to help out.