parcel-bundler / parcel

The zero configuration build tool for the web. πŸ“¦πŸš€
https://parceljs.org
MIT License
43.37k stars 2.27k forks source link

importing css modules results in Error: "Bundles must have unique names" #7842

Open goldylucks opened 2 years ago

goldylucks commented 2 years ago

πŸ› bug report

// index.js
import * as classes from './index.module.css'

results in

Error: Bundles must have unique names

πŸŽ› Configuration (.babelrc, package.json, cli command)

// .parcelrc
{
    "extends": "@parcel/config-webextension"
}

// babel.config.js
module.exports = {
    plugins: [
        [
            "@babel/plugin-proposal-decorators",
            {
                legacy: true,
            },
        ],
        [
            "@babel/plugin-proposal-class-properties",
            {
                loose: true,
            },
        ],
    ],
    presets: [
        [
            "@babel/preset-env",
            {
                targets: {
                    node: "current",
                },
                loose: true,
            },
        ],
        "@babel/preset-react",
    ],
}

// package.json
{
    "private": true,
    "scripts": {
        "build": "parcel build source/manifest.json --no-content-hash --no-source-maps --dist-dir distribution --no-cache --detailed-report 0",
        "lint": "run-p lint:*",
        "lint-fix": "run-p 'lint:* -- --fix'",
        "lint:css": "stylelint source/**/*.css",
        "lint:js": "xo",
        "eslint": "eslint source/**/*.js source/**/*.jsx",
        "test": "run-p lint:* build",
        "watch": "parcel watch source/manifest.json --dist-dir distribution --no-cache --no-hmr"
    },
    "husky": {
        "hooks": {
            "pre-commit": "lint-staged"
        }
    },
    "lint-staged": {
        "source/**/*.{js,jsx}": [
            "eslint",
            "prettier --write"
        ],
        "source/**/*.css": [
            "prettier --write"
        ]
    },
    "browserslist": [
        "last 1 Chrome version",
        "last 1 Firefox version"
    ],
    "xo": {
        "envs": [
            "browser"
        ],
        "rules": {
            "no-unused-vars": [
                "error",
                {
                    "varsIgnorePattern": "browser"
                }
            ]
        }
    },
    "stylelint": {
        "extends": "stylelint-config-xo"
    },
    "dependencies": {
        "@reduxjs/toolkit": "^1.8.0",
        "bootstrap": "^5.1.3",
        "react": "^17.0.2",
        "react-bootstrap": "^2.2.1",
        "react-bootstrap-typeahead": "^6.0.0-alpha.9",
        "react-dom": "^17.0.2",
        "react-redux": "^7.2.6",
        "react-toastify": "^8.2.0",
        "redux-saga": "^1.1.3",
        "webext-options-sync": "^3.0.1",
        "webextension-polyfill": "^0.8.0"
    },
    "devDependencies": {
        "@babel/core": "^7.17.7",
        "@babel/eslint-parser": "^7.17.0",
        "@babel/plugin-proposal-class-properties": "^7.16.7",
        "@babel/plugin-proposal-decorators": "^7.17.2",
        "@babel/preset-env": "^7.16.11",
        "@babel/preset-react": "^7.16.7",
        "@parcel/config-webextension": "^2.3.2",
        "@parcel/transformer-image": "^2.3.2",
        "axios": "^0.26.1",
        "eslint": "^8.11.0",
        "eslint-plugin-import": "^2.25.4",
        "eslint-plugin-react": "^7.29.3",
        "husky": "4",
        "lint-staged": "^12.3.7",
        "npm-run-all": "^4.1.5",
        "parcel": "^2.3.2",
        "postcss": "^8.0.0",
        "postcss-modules": "^4.3.0",
        "prettier": "^2.5.1",
        "process": "^0.11.10",
        "rollup-plugin-import-css": "^3.0.3",
        "stylelint": "^14.5.3",
        "stylelint-config-xo": "^0.20.1",
        "xo": "^0.48.0"
    },
    "webExt": {
        "sourceDir": "distribution"
    }
}

πŸ€” Expected Behavior

should work

😯 Current Behavior

throws the error

Error: Bundles must have unique names

  AssertionError [ERR_ASSERTION]: Bundles must have unique names
  at BundlerRunner.nameBundles
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/core/lib/requests/BundleGraphRequest.js:343:23)
  at async BundlerRunner.bundle
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/core/lib/requests/BundleGraphRequest.js:286:5)
  at async RequestTracker.runRequest
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/core/lib/RequestTracker.js:725:20)
  at async Object.run
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/core/lib/requests/ParcelBuildRequest.js:62:7)
  at async RequestTracker.runRequest
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/core/lib/RequestTracker.js:725:20)
  at async Parcel._build
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/core/lib/Parcel.js:397:11)
  at async Parcel._startNextBuild
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/core/lib/Parcel.js:298:24)
  at async $b0fd219fea43bcac$export$2e2bcd8739ae039._runFn
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/utils/lib/index.js:32645:13)
  at async $b0fd219fea43bcac$export$2e2bcd8739ae039._next
  (/Users/Goldy/apps/web-extension/node_modules/@parcel/utils/lib/index.js:32638:9)

πŸ’ Possible Solution

no idea πŸ€·β€β™€οΈ

πŸ”¦ Context

trying to use css modules (alongside global css and npm css files, tho those work fine)

πŸ’» Code Sample

// index.js
import * as classes from './index.module.css'

🌍 Your Environment

Software Version(s)
Parcel 2.3.2
Node v16.13.2
npm/Yarn yarn 1.22.17
Operating System Mac OS Monterey 12.2.1 (21D62) (Apple sillicon m1)
goldylucks commented 2 years ago

Also tried adding this file with no effect:

// .postcssrc.js
module.exports = {
    modules: true,
    plugins: {
        "postcss-modules": {
            generateScopedName: "[folder]__[local]___[hash:base64:6]",
        },
    },
}
devongovett commented 2 years ago

do you have a reproduction we can try?

goldylucks commented 2 years ago

sure, here it is: https://github.com/goldylucks/browser-extension-template

thanks for the help and getting back to me so promptly!

devongovett commented 2 years ago

Appears to be generating two bundles named content.css. This is because there is a content.css file referenced from manifest.json (marked as needsStableName, not sure if required), and the sibling CSS file for content.js also gets named content.css. I guess the namer needs to be a bit smarter about it.

Note: this is not specific to CSS modules, it could happen with any CSS file. As a workaround, you could either rename content.js or content.css to something else for now.

goldylucks commented 2 years ago

but if I rename the file the collision will just happen for the new name no?

or am I missing smthn here?

Shinyaigeek commented 2 years ago

Parcel generates {name}.css from {name}.js file which imports CSS files. In this case, parcel generates content.css from content.js and this will lead a collision fo filename. so to rename content.js to {other than content}.js or content.css to {other than content}.css can be workaround.

101arrowz commented 2 years ago

CSS Modules aren't currently supported in the web extension config. Although #7050 will fix this specific issue, it's still probably a good idea to work around name collisions in the default namer even if needsStableName is present on multiple assets with the same name.

CxRes commented 2 years ago

I am seeing the same bug with SVG files when I use parcel-namer-custom plugin. The plugin logs that the name() is being repeatedly being called on the same SVG file (I suspect this is because multiple references are being generated by prior SVG plugins). In any case, this prevents renaming the file unless one uses a hash in the renamed file.

Edit: I can confirm this is caused by SVG transformer plugin on larger SVG files. Turning it off will remove multiple invocation in the namer plugin.

TechQuery commented 2 years ago

As the reason of #7230, I tried to remove import 'index.css'; manually, so I disabled the Source Map in package.json to avoid incorrect Debugging Break-point:

{
    "devDependencies": {
        "@parcel/packager-ts": "~2.7.0",
        "@parcel/transformer-less": "~2.7.0",
        "@parcel/transformer-typescript-types": "~2.7.0",
        "parcel": "~2.7.0",
        "typescript": "~4.7.4"
    },
    "browserslist": "> 0.5%, last 2 versions, not dead",
    "targets": {
+        "default": {
+            "sourceMap": false
+        },
        "main": {
            "optimize": true
        }
    },
    "scripts": {
        "build": "parcel build"
    }
}

But I got the same error:

AssertionError [ERR_ASSERTION]: Bundles must have unique names

If I replace the JSON option with the CLI parameter --no-source-maps, the building succeed with a warning:

> 4 | import * as style from './index.module.less';
>   |                        ^^^^^^^^^^^^^^^^^^^^^^ Cannot find module './index.module.less' or its corresponding type declarations.

Guys of @parcel-bundler team, you can find the reproduce code in idea2app/Idea-React#20.