remarkjs / react-markdown

Markdown component for React
https://remarkjs.github.io/react-markdown/
MIT License
12.98k stars 866 forks source link

Module "assert" has been externalized for browser compatibility and cannot be accessed in client code. #632

Closed Snnny closed 3 years ago

Snnny commented 3 years ago

Initial checklist

Affected packages and versions

7.0.0

Link to runnable example

No response

Steps to reproduce

import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm' <ReactMarkdown children={'# hello'} remarkPlugins={[remarkGfm]}>

Expected behavior

show hello

Actual behavior

Uncaught Error: Module "assert" has been externalized for browser compatibility and cannot be accessed in client code. at Object.get (browser-external:assert:3) at go (create-tokenizer.js:213) at main (create-tokenizer.js:198) at Object.write (create-tokenizer.js:124) at fromMarkdown (index.js:117) at parser (index.js:15) at Function.parse2 [as parse] (index.js:273) at ReactMarkdown (react-markdown.js:102) at renderWithHooks (react-dom.development.js:14985) at mountIndeterminateComponent (react-dom.development.js:17811)

Runtime

Node v12

Package manager

yarn v1

OS

macOS

Build and bundle tools

Vite

wooorm commented 3 years ago

Vite seems to specify that, in development, development code is loaded: https://github.com/vitejs/vite/blob/ed16488591b7dfac7e54d96f67c6f3674368b0cc/packages/vite/src/node/plugins/resolve.ts#L654. The development code for micromark includes assertions: https://github.com/micromark/micromark#size--debug. As importing certain builtin node modules is quite common, e.g., code often depends on path or url, I’m assuming you can configure vite to include assert, too. Other bundlers allow this as well, so Vite should too. These options might help: https://vitejs.dev/config/#dep-optimization-options

github-actions[bot] commented 3 years ago

Hi! This was closed. Team: If this was fixed, please add phase/solved. Otherwise, please add one of the no/* labels.

Snnny commented 3 years ago

but I never config ,here is my vite.config.ts:

export default () => {
  return {
    // css 预处理器
    css: {
      preprocessorOptions: {
        less: {
          javascriptEnabled: true,
        },
      },
    },
    // 别名
    resolve: {
    },
    // 接口代理
    server: {
      proxy: {
      },
    },
    // 打包
    build: {
      rollupOptions: {
        cssCodeSplit: true,
      },
      outDir: currConf.outputPath,
      commonjsOptions: { transformMixedEsModules: true },
    },
    // 插件
    plugins: [
      reactRefresh(),
      checker({
        typescript: true,
        overlay: false,
        // enableBuild: false,
        eslint: { files: ['./src'], extensions: ['.ts', '.tsx'] },
      }),
    ],
  };
};
ChristianMurphy commented 3 years ago

https://github.com/vitejs/vite/discussions/4479#discussioncomment-1121552 suggests using browserify polyfills. Or as @wooorm suggests https://vitejs.dev/config/#dep-optimization-options may be able to be used to tell vite to include a dependency like assert anyway.

or2008 commented 3 years ago

getting the same error with webpack 5, why is the issue closed?

wooorm commented 3 years ago

because it’s not an issue here, but with how your bundler is configured.

mellson commented 3 years ago

Hi @Snnny where you able to fix your issue? Because I'm running into the same issues in my dev environment and hasn't been able to figure out how to fix it 🤔

Update I got mine working by install this assert package as a dev dependency and adding a process.env to my vite config:

config = defineConfig({
    define: {
      "process.env": {},
    },

    plugins: [reactRefresh()],
  })

But interested to know if anyone has a smarter solution?

or2008 commented 3 years ago

because it’s not an issue here, but with how your bundler is configured.

true, but I would expect a frontend library to avoid relying on node.js modules

Hi @Snnny where you able to fix your issue? Because I'm running into the same issues in my dev environment and hasn't been able to figure out how to fix it 🤔

Update I got mine working by install this assert package as a dev dependency and adding a process.env to my vite config:

config = defineConfig({
    define: {
      "process.env": {},
    },

    plugins: [reactRefresh()],
  })

But interested to know if anyone has a smarter solution?

this is how I solved it:

...
  resolve: {
            alias: {
                '@src': resolve(__dirname, '../../src'),
            },
            extensions: ['.json', '.ts', '.js'],
            fallback: {
                'buffer': require.resolve('buffer/'),
                'stream': require.resolve('stream-browserify/'),
                'assert': require.resolve('assert/') // don't forget  to install assert (npm i --save-dev assert)
            }
        },
...

  plugins: [
            new ProvidePlugin({
                process: 'process/browser',
                Buffer: ['buffer', 'Buffer']
            })
        ],
wooorm commented 3 years ago

Well, its a bit more complex because: a) micromark is not a frontend library, it's agnostic b) micromark uses a very new, node specific feature, to load extra debugging code if --conditions=development is passed as a flag to node. Now, Vite is also extremely new, and for some reason they also decided to pass that flag when not in production. I can somewhat understand that, but there is no precedent here.

JounQin commented 3 years ago

I'm using browserify assert polyfill on development, and @rollup/plugin-strip and alias: { assert: 'src/libs/none.ts' } on production. src/line/none.ts is an empty file. It runs very well now. But I'd prefer it can be 'fixed' in micromark.

wooorm commented 3 years ago

and alias: { assert: 'src/libs/none.ts' } on production

micromark does not include assert in production, so that should not be needed.

JounQin commented 3 years ago

micromark does not include assert in production, so that should not be needed.

Wow, that's great to hear.

mellson commented 3 years ago

@JounQin can you share your config file so I can see how you use the assert polyfill?

JounQin commented 3 years ago

@JounQin can you share your config file so I can see how you use the assert polyfill?

Just yarn add -D assert, and add 'process.env.NODE_DEBUG': undefined into define of vite.config.ts for node-util.

olejorgenb commented 2 years ago

To avoid messing with the vite config add this to packages.json: (How wonderful that comments is not a thing in json files /s)

EDIT: these only need to be added temporarily. Run yarn install and then remove them. Subsequent installs does not downgrade them.

    "resolutions": {
        "micromark-util-symbol": ">=1.0.1",
        "micromark-util-subtokenize": ">=1.0.2",
        "micromark-util-html-tag-name": ">=1.1.0",
        "micromark-util-encode": ">=1.0.1",
        "micromark-util-decode-string": ">=1.0.2",
        "micromark-factory-title": ">=1.0.2",
        "micromark-factory-label": ">=1.0.2",
        "micromark-core-commonmark": ">=1.0.6",
        "micromark-build": ">=1.1.0",
        "mdast-util-from-markdown": ">=1.2.0"
    }

Ref:

ChristianMurphy commented 2 years ago

I'd recommend against pinning outdated/unmaintained versions of dependencies.

Instead consider the polyfilling approach suggested in https://github.com/remarkjs/react-markdown/issues/632#issuecomment-909123237

wooorm commented 2 years ago

Assert isn't used for about a year now. Run 'npm install' or equivent to get updates.

olejorgenb commented 2 years ago

Assert isn't used for about a year now. Run 'npm install' or equivent to get updates.

Not directly maybe, but I got the same and similar errors from the the transient dependency micromark (I'm at react-markdown 8.0.3):

$ yarn list | grep react-markdown
├─ react-markdown@8.0.3
$ yarn why micromark-factory-label
=> Found "micromark-factory-label@1.0.0"
info Reasons this module exists
   - "_project_#react-markdown#remark-parse#mdast-util-from-markdown#micromark#micromark-core-commonmark" depends on it

yarn install (not sure about npm) did not upgrade these transient dependencies as a result of upgrading react-markdown. Deleting my lock-file and node_modules and reinstalling would likely have worked come to think of it.

I can report that yarn does not downgrade the packages after removing the resolutions section after a install, so this step can luckily be used non-permanently.

I'd recommend against pinning outdated/unmaintained versions of dependencies.

They're not pinned though? Only a lower limit on the versions. But yeah, it's not pretty. But neither is poly-filling something for a dependency IMO.

wooorm commented 2 years ago
$ npm info micromark-factory-label version
1.0.2

yarn install (not sure about npm) did not upgrade these transient dependencies

It should.

olejorgenb commented 2 years ago

Not sure how valuable it is to continue this thread further, but I ended up digging more for my own sake, so might as well note it here in the off-chance someone find it helpful.

Based on this I believe yarn (1.x) does not touch transient dependencies unless required when using a lockfile [1]. This (https://github.com/yarnpkg/yarn/issues/4986) open yarn issue about yarn upgrade seems to be related, although running yarn upgrade does upgrade the micromark-* packages here. (but not yarn upgrade react-markdown@8.0.3)

To avoid havoc in the lockfile the temporarily "resolutions" { ... } section seems like a cumbersome trick to make yarn do what I want.

That being said, my project contains a number of dependencies so there might be something going on with one package blocking another which I've missed. Maybe the workspaces alter the behavior as well?

PS: I didn't understand what you meant by the npm info micromark-factory-label version command? This just shows the latest version of the package, no?

[1] I guess that makes sense in some way - less changes -> less chance of trouble? But the upgraded package is likely tested the most using the most up to date dependencies so I'm not convinced of this logic. Assuming yarn is able to distinguish transiently-dependent-only packages from "root" packages my gut-feeling is that it would be better to upgrade them. The equation might be more complex if the packages is dependent on by multiple other packages though.

wooorm commented 2 years ago

PS: I didn't understand what you meant by the npm info micromark-factory-label version command? This just shows the latest version of the package, no?

Correct, it does. Which was higher than the one you had!


I’ll hide this subthread, for further readers: remove your locks and install again and you won’t hit this old issue!