Skip to content

Circulars dependencies are causing infinite loop #1193

@layershifter

Description

@layershifter

Environment

  • Linaria version: @linaria/babel-preset@4.3.3, @linaria/react@4.3.3, @linaria/webpack-loader@4.1.11
  • Bundler (+ version): Webpack 5
  • Node.js version: 16
  • OS: N/A

Description

The issue happens in the real project, there we will have following import path:

{
  name: '<root>/packages/data/data-resolver-types/generated/foo.ts',
  children: [
    {
      name: '<root>/packages/data/data-types-common/index.ts',
      children: [
        {
          name: '<root>/packages/data/data-types-common/src/fragments/index.ts',
          children: [
            {
              name: '<root>/packages/data/data-types-common/src/fragments/baz.ts',
              children: [
                {
                  name: '<root>/packages/data/data-types-common/index.ts',
                  circular: true
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Notice that <root>/packages/data/data-types-common/index.ts is circularly referenced.

Webpack successfully builds such code, but once @linaria/webpack-loader is in place build freezes (actually it's an infinite loop).


The easiest way to find out that is to go to node_modules/@linaria/babel-preset/lib/transform-stages/1-prepare-for-eval.js and modify it to log active mutexes:

const mutexes = new Map();
+setInterval(() => {
+   console.log('mutexes', mutexes)
+}, 2000)

It outputs something like that:

mutexes Map(3) {
  '/linaria-circulars-issue/src/index.js' => Promise { <pending> },
  '/linaria-circulars-issue/src/pkg-a/index.js' => Promise { <pending> },
  '/linaria-circulars-issue/src/pkg-a/styles.js' => Promise { <pending> }
}

Notice: these promises will be never resolved 💥

I created a simple repro of this in https://github.com/layershifter/linaria-circulars-issue. In my simplified case Webpack does not go into infinite loop, it just outputs nothing:

$ yarn b:webpack:linaria
...

Without circulars it complies successfully:

$ yarn b:webpack:linaria-no-circulars
asset main.js 2.31 KiB [compared for emit] (name: main)
asset styles.css 24 bytes [compared for emit] (name: main)
Entrypoint main 2.33 KiB = styles.css 24 bytes main.js 2.31 KiB
orphan modules 2.79 KiB (javascript) 937 bytes (runtime) [orphan] 8 modules
runtime modules 274 bytes 1 module
webpack 5.75.0 compiled successfully in 520 ms

I also tried Webpack, Rollup and esbuild without Linaria, all they pass:

$ yarn b:webpack
asset main.js 690 bytes [emitted] (name: main)
orphan modules 338 bytes [orphan] 4 modules
./src/index.js + 4 modules 488 bytes [not cacheable] [built] [code generated]
webpack 5.75.0 compiled successfully in 57 ms
$ yarn b:rollup

./src/index.js → ./dist/rollup/main.js...
(!) Circular dependency
src/pkg-a/index.js -> src/pkg-a/styles.js -> src/pkg-a/index.js
created ./dist/rollup/main.js in 19ms

Notice that Rollup complains about circulars, but builds it

yarn b:esbuild

  dist/esbuild/main.js  801b 

⚡ Done in 3ms

Reproducible Demo

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions