Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESM library generated with rollup-plugin-postcss throws Cannot find module '../node_modules/style-inject/dist/style-inject.es.js' #381

Open
mummybot opened this issue Jun 16, 2021 · 15 comments · May be fixed by #395

Comments

@mummybot
Copy link

Apologies if this is more of a usage question than a bug, I have posted here at Stackoverflow.

We are maintaining an internal library which is exporting ESM modules using Rollup. We have just recently switched to using CSS modules, which we have set with rollup-plugin-postcss. We want to inject these styles into the head rather than have an external file.

Our built bundle generates the ESM file with:

import styleInject from '../node_modules/style-inject/dist/style-inject.es.js';

Our consuming library then fails with

 Uncaught Error: Cannot find module '../node_modules/style-inject/dist/style-inject.es.js'

I would expect the ESM export to import styleInject from 'style-inject' and style-inject to be included in the package-lock.json as a dependency. Even manually adding the dependency as part of our library which then includes it in the consuming app doesn't allow it to resolve. What is the correct way of using CSS Modules and injecting into the head for the consumer of a library?

rollup.config.js

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import json from '@rollup/plugin-json';
import postcss from 'rollup-plugin-postcss';
import pkg from './package.json';
import fg from 'fast-glob';
import path from 'path';

export default [
  {
    input: 'src/index.js',
    external: external(),
    output: [
      {
        name: '@my/packageName',
        file: pkg.module,
        format: 'es',
        sourcemap: true,
      },
    ],
    plugins: [
      {
        name: 'watch-external',
        async buildStart() {
          const files = await fg(['src/index.d.ts', 'playground/**/*']);
          for (let file of files) {
            this.addWatchFile(path.resolve(file));
          }
        },
      },
      json(),
      postcss({
        modules: true,
      }),
      babel({
        exclude: /node_modules/,
        babelHelpers: 'runtime',
        babelrc: false,
        presets: [
          [
            '@babel/preset-env',
            {
              modules: false,
              useBuiltIns: 'entry',
              corejs: 3,
              targets: {
                ie: 11,
              },
            },
          ],
          '@babel/preset-react',
        ],
        plugins: [
          '@babel/plugin-transform-runtime',
          '@babel/plugin-proposal-class-properties',
          '@babel/plugin-proposal-export-namespace-from',
        ],
      }),
      commonjs(),
    ],
  },
];

function external() {
  const { dependencies = {}, peerDependencies = {} } = pkg;

  const externals = [
    ...Object.keys(dependencies),
    ...Object.keys(peerDependencies),
  ];

  return id =>
    // match 'lodash' and 'lodash/fp/isEqual' for example
    externals.some(dep => id === dep || id.startsWith(`${dep}/`));
}
@mummybot
Copy link
Author

mummybot commented Jun 16, 2021

I've fixed this for our project by doing two things:

  1. Including style-inject in the library's dependencies
  2. String replacing the built .esm file: '../node_modules/style-inject/dist/style-inject.es.js' to 'style-inject'.

It works, but this seems like a hack for what should just work out of the box. Is there a reason for the relative import path to style-inject? If so, can we make it configurable?

@mummybot
Copy link
Author

I'll raise a PR shortly

@dandrewgarvin
Copy link

dandrewgarvin commented Jul 15, 2021

We are experiencing this issue as well, and have probably a very similar solution to @mummybot. For anybody else that encounters this problem while it remains unsolved in this plugin, here was the custom inline-plugin we built:

// rollup.config.js
export default {
  // other rollup configurations...

  plugins: [
    // other rollup plugins...

    postcss(),

    {
        name: 'Custom Rollup Plugin`',

        generateBundle: (options, bundle) => {
          Object.entries(bundle).forEach(entry => {

            // early return if the file we're currently looking at doesn't need to be acted upon by this plugin
            if (!entry[0].match(/.*(.scss.js)$/)) {
              return;
            }

            // this line only runs for .scss.js files, which were generated by the postcss plugin.
            // depending on the use-case, the relative path to style-inject might need to change
            bundle[entry[0]].code = entry[1].code.replace(
              '../../node_modules/style-inject/dist/style-inject.es.js',
              'style-inject',
            );
          });
        },
      }
  ]
}

@mrcrazylee
Copy link

mrcrazylee commented Jul 17, 2021

Looks like somebody already created a PR in May, but some tests are failing.
https://github.com/egoist/rollup-plugin-postcss/pull/375/files

mummybot added a commit to mummybot/rollup-plugin-postcss that referenced this issue Aug 24, 2021
@mummybot
Copy link
Author

Let's see if this gets reviewed and merged 🙏

@MrJadaml
Copy link

MrJadaml commented Sep 20, 2021

We are also running into this issue. Would love to see this get merged in!

Update: actually don't care if this gets merged in as we have found that style-inject has a flaw in that it will inject style tags in reverse order causing css priority issues. egoist/style-inject#23. The lib has also not been touched in 4 years, so don't expect any fixes to go in. Rollup should move away from depending on this lib.

@egorgrushin
Copy link

egorgrushin commented Aug 4, 2022

This is not a bug at all. It works properly because stylesInject is just a function from 'styles-inject' package, so we can allow it to be bundled. But it is not bundled because most likely you have this setting in your rollup.config.js:

external: [
    /node_modules/
]

So, replace it with a code bellow and it will work:

external: (id) => {
    if (/style-inject/.test(id)) return false;
    if (/node_modules/.test(id)) return true;
    return false;
},

also, you can write a regexp for it instead

@renatorroliveira
Copy link

The above answer is incorrect since it's assuming you do want to bundle everything together.

When you are generating a library with preserved modules, the nasty node_modules folder for the relative import to work is not packed up by NPM. The configuration is definitely required, regardless of rollup keep using styleInject or not. When generating this kinda library you don't want relative imports and usually will prefer using peer dependencies instead (of some other way to bundle the dependency once for the final bundle).

@renatorroliveira
Copy link

If you do want to abide for the way rollup decided to implement this, you can "force" NPM to pack the nested modules by adding the folder explicitly on your package.json:

    "files": [
        "dist/*",
        "dist/node_modules/*"
    ],

@WahidN
Copy link

WahidN commented Mar 30, 2023

Has this been resolved? I got this issue too

@icy0307
Copy link

icy0307 commented Jun 19, 2023

As a dependency , style-injectshould not be bundles with library. This pr also would reduce final bundle css, when using multiple libraries transformed with rollup-plugin-postcss
@egoist Could you accept this pr?

@ofqwx
Copy link

ofqwx commented Aug 17, 2023

Is there any update on this? I'm running the same issue

@U-4-E-A
Copy link

U-4-E-A commented Oct 9, 2023

Any update here? I have the same issue. Thanks,

@SunHuawei
Copy link

We are experiencing this issue as well, and have probably a very similar solution to @mummybot. For anybody else that encounters this problem while it remains unsolved in this plugin, here was the custom inline-plugin we built:

// rollup.config.js
export default {
  // other rollup configurations...

  plugins: [
    // other rollup plugins...

    postcss(),

    {
        name: 'Custom Rollup Plugin`',

        generateBundle: (options, bundle) => {
          Object.entries(bundle).forEach(entry => {

            // early return if the file we're currently looking at doesn't need to be acted upon by this plugin
            if (!entry[0].match(/.*(.scss.js)$/)) {
              return;
            }

            // this line only runs for .scss.js files, which were generated by the postcss plugin.
            // depending on the use-case, the relative path to style-inject might need to change
            bundle[entry[0]].code = entry[1].code.replace(
              '../../node_modules/style-inject/dist/style-inject.es.js',
              'style-inject',
            );
          });
        },
      }
  ]
}

This helped me out, thanks to @dandrewgarvin !
Just trying to make it more generic by changing the search value to a regex

        postcss(),
        { 
            name: 'Replace style-inject Rollup Plugin`', // it has to be after `postcss()`
            generateBundle: (options, bundle) => {
                Object.entries(bundle).forEach(entry => {
                    // early return if the file we're currently looking at doesn't need to be acted upon by this plugin
                    if (!entry[0].match(/.*(.scss.js)$/)) {
                        return;
                    }

                    // this line only runs for .scss.js files, which were generated by the postcss plugin.
                    bundle[entry[0]].code = entry[1].code.replace(
                        /[./]*\.\/node_modules\/style-inject\/dist\/style-inject.es.js/,
                        'style-inject',
                    );
                });
            },
        },

@marselbairam
Copy link

marselbairam commented Jan 27, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet