Less.js: Missing selector when using sourcemaps, plugins, and compiling Less files in parallel

Created on 14 Dec 2020  ·  29Comments  ·  Source: less/less.js

I have some code like bottom.

    @root-name: business-bundle
    /* other file */
    .@{root-name} .wrapper{
        /* css... */
    }

When webpack use less 3.12.2, that is ok. But when use 3.13.0, webpack build error.
image

bug medium priority research needed

Most helpful comment

@PengJiyuan @kirazxyun @Justineo etc please try testing with [email protected]

All 29 comments

@TopGrd That really isn't enough to go on, especially when it's an error in a package that Less doesn't maintain. Can you make a test repo with a minimal test case? Also, does this error occur when just using lessc to compile your Less code?

Having a similar issue with v3.13.0 - 3.12.2 working for me as well.

image

It's a huge project, so nearly impossible to find where in the less file this happend.

@endbay @TopGrd

I'm not sure what's expected here. With no reproducible example, and with the error not thrown in Less itself, there's no hope in a resolution. Someone will need to set a breakpoint at that error and see what selector was expected and why it isn't present.

@TopGrd

One clue, this Less code is invalid:

    @root-name: business-bundle
    /* other file */
    .@{root-name} .wrapper{
        /* css... */
    }

@root-name: business-bundle is missing a semi-colon. So it could be that you have some library layered on top of Less which is expecting an error, doesn't find one, and tries to go ahead and parse Less's output, but fails with this "missing selector" error. That's just a guess, since I have no repo to look at.

I'm experiencing a similar problem in 3.13.0. (Still trying to find out a minimal reproduction.)

Related code looks like:

// button.less
@import "./lib.less";

.@{prefix}-button {
  color: red;

  &:hover {
    color: blue;
  }
}
// lib.less
@import "./vars"; // where @prefix is defined

Which is compiled as:

{
  color: red;
}

:hover {
  color: blue;
}

It's weird that no compilation error occurred.

@matthew-dean It is a very huge project where error occurred. I am trying to reproduce it in a demo

@TopGrd

One clue, this Less code is invalid:

  @root-name: business-bundle
    /* other file */
  .@{root-name} .wrapper{
      /* css... */
  }

@root-name: business-bundle is missing a semi-colon. So it could be that you have some library layered on top of Less which is expecting an error, doesn't find one, and tries to go ahead and parse Less's output, but fails with this "missing selector" error. That's just a guess, since I have no repo to look at.

@root-name: business-bundle; Sorry, this is my code. It have a semi-colon.

I'm experiencing a similar problem in 3.13.0. (Still trying to find out a minimal reproduction.)

Related code looks like:

// button.less
@import "./lib.less";

.@{prefix}-button {
  color: red;

  &:hover {
    color: blue;
  }
}
// lib.less
@plugin "~some-less-plugin"; // where @prefix is injected which preprocessing plugins

Which is compiled as:

{
  color: red;
}

:hover {
  color: blue;
}

It's weird that no compilation error occurred.

I use style-resources-loader to inject some global variables too. Maybe it has something to do with that?

{
  test: /\.less$/i,
  use: [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        hmr: process.env.NODE_ENV === 'development',
        reloadAll: true,
      },
    },
    {
      loader: 'css-loader',
    },
    {
      loader: 'postcss-loader',
      options: {
        config: {
          path: path.resolve(__dirname, '../postcss.config.js'),
        },
      },
    },
    {
      loader: 'less-loader',
      options: {
        lessOptions: {
          javascriptEnabled: true,
          paths: [path.resolve(cwd, 'node_modules')],
        },
      },
    },
    {
      loader: 'style-resources-loader',
      options:{
            patterns: path.resolve(
              cwd,
              './node_modules/@somemodule/style/index.less',
            ),
            injector: 'prepend',
          },
    },
  ],
},

My code:
image

debugger less.render output: no selector
image

The variable @{bundle-root-class} is settingBundle. It looks like the variables in the first line are not compiled?

Still cannot find out a simple reproduction. It's very weird that when hot module replacement is triggered and the compiled output of the changed file seems to be correct. And the problem only occurs for selector interpolation:

@import "./lib.less";

.@{prefix}-button {
  val: @prefix;
}

Compiles to:

{
  val: foo;
}

(Note the whole selector is missing, not only the interpolated part.)

@Justineo

the compiled output of the changed file seems to be correct

Can you expand on this a bit more? The compiled output from Less seems to be correct, but it's not getting replaced correctly?

It's very weird that when hot module replacement is triggered and the compiled output of the changed file seems to be correct.

@Justineo This is a helpful clue. It's likely related to the resolution of this: https://github.com/less/less.js/issues/3434

In short, tree caching was removed from Less for a time, but it seemed to have too much of a negative performance impact in some scenarios, so I put it back in. It could be that Less is therefore not resetting some state of import trees, which ONLY causes an issue in a "live" environment where less.parse is called multiple times. Hmm, I wonder if I can test that theory in a reproduction.

@Justineo @TopGrd @endbay

Unfortunately, I still cannot reproduce this issue, so it's not debuggable. ☹️ If someone can make a repo where it's easily reproducible, I could step through it.

I'm experiencing a similar problem in 3.13.0. (Still trying to find out a minimal reproduction.)
Related code looks like:

// button.less
@import "./lib.less";

.@{prefix}-button {
  color: red;

  &:hover {
    color: blue;
  }
}
// lib.less
@plugin "~some-less-plugin"; // where @prefix is injected which preprocessing plugins

Which is compiled as:

{
  color: red;
}

:hover {
  color: blue;
}

It's weird that no compilation error occurred.

I use style-resources-loader to inject some global variables too. Maybe it has something to do with that?

{
  test: /\.less$/i,
  use: [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        hmr: process.env.NODE_ENV === 'development',
        reloadAll: true,
      },
    },
    {
      loader: 'css-loader',
    },
    {
      loader: 'postcss-loader',
      options: {
        config: {
          path: path.resolve(__dirname, '../postcss.config.js'),
        },
      },
    },
    {
      loader: 'less-loader',
      options: {
        lessOptions: {
          javascriptEnabled: true,
          paths: [path.resolve(cwd, 'node_modules')],
        },
      },
    },
    {
      loader: 'style-resources-loader',
      options:{
            patterns: path.resolve(
              cwd,
              './node_modules/@somemodule/style/index.less',
            ),
            injector: 'prepend',
          },
    },
  ],
},

+1

Less @plugin + sourcemap will cause this problem

@matthew-dean 🙏

@PengJiyuan Can you create a reproducible example in a cloneable repo?

+1
image
I think the problem is caused by this code. The tree node have wrong fileInfo In the case of parallel, which causes the inputSource is undefined.

+1
image
I think the problem is caused by this code. The tree node have wrong fileInfo In the case of parallel, which causes the inputSource is undefined.

@matthew-dean Wait a minute, we create a mini repo. We have located this line of code, hope to help you solve it quickly...

+1
image
I think the problem is caused by this code. The tree node have wrong fileInfo In the case of parallel, which causes the inputSource is undefined.

This line of code has appeared since 3.10.0

@PengJiyuan Can you create a reproducible example in a cloneable repo?

https://github.com/kirazxyun/less-question

This repo can reproduce the problem. You can run with 'npm run build',then view the results in the dist folder.

@PengJiyuan Can you create a reproducible example in a cloneable repo?

https://github.com/kirazxyun/less-question

This repo can reproduce the problem. You can run with 'npm run build',then view the results in the dist folder.

@matthew-dean

@matthew-dean We use @plugin and it affects all our projects, please help us 🙏

@PengJiyuan You're right, the code in question shouldn't fail outputting the chunk if source map building doesn't work. It should be like:

                if (inputSource === undefined) {
                    this._css.push(chunk);
                    return;
                }

That would be a short-term fix, with the longer term fix being figuring out why one of the files has an incorrect import mapping. (It's probably being re-used when compiled in parallel.)

So I can do the temporary band-aid solution soon, and figure out the cause after.

@PengJiyuan @kirazxyun @Justineo etc please try testing with [email protected]

Problem solved with [email protected]. Thank you Matt!

@matthew-dean It works, thanks 🙏

@matthew-dean confirm that problem is solved with [email protected], hoping for a official release soon

It is solved with [email protected].

3.13.1 published

4.0.0 is also published, which contains this fix.

Was this page helpful?
0 / 5 - 0 ratings