parcel icon indicating copy to clipboard operation
parcel copied to clipboard

css import in bundled ES module

Open sKopheK opened this issue 1 year ago • 5 comments

🐛 bug report

🎛 Configuration

package.json

{
  ...
  "source": "src/App/index.js",
  "module": "dist/output.js",
  "scripts": {
    ...
    "start": "parcel src/index.html --dist-dir debug",
    "build": "parcel build --no-content-hash --no-source-maps"
  },
  "targets": {
    "module": {
      "context": "browser",
      "includeNodeModules": true,
      "optimize": true
    }
  },
  "alias": {
    "process": {
      "global": "{}"
    }
  },
  "dependencies": {
    "@popperjs/core": "^2.11.6",
    "classnames": "^2.3.2",
    "css-loader": "^6.8.1",
    "cytoscape": "^3.25.0",
    "cytoscape-fcose": "^2.2.0",
    "cytoscape-node-html-label": "^1.2.2",
    "cytoscape-popper": "^2.0.0",
    "html2canvas": "^1.4.1",
    "lodash.debounce": "^4.0.8",
    "redux-batched-subscribe": "^0.1.6",
    "redux-saga": "^1.2.3",
    "tippy.js": "^2.6.0",
    "vanjs-core": "^1.2.1"
  },
  "devDependencies": {
    "@parcel/optimizer-data-url": "^2.11.0",
    "@parcel/transformer-inline-string": "^2.11.0",
    "@parcel/transformer-sass": "^2.11.0",
    "@reduxjs/toolkit": "^1.9.5",
    "@types/cytoscape": "^3.19.11",
    "@types/cytoscape-fcose": "^2.2.4",
    "@types/redux-batched-subscribe": "^0.1.4",
    "parcel": "^2.11.0",
    "process": "^0.11.10"
  }
}

tsconfig.json

{
    "compilerOptions": {
        "baseUrl": "./src",
        "target": "ES2019",
        "module": "ES2020",
        "allowJs": true,
        "checkJs": true,
        "moduleResolution": "node",
        "paths": {
            "/*": [
                "../*"
            ],
        }
    },
    "exclude": [
        "dist",
        "debug",
        "public/example",
        "node_modules"
    ]
}

🤔 Expected Behavior

css should not be imported into JS bundle

😯 Current Behavior

After build is done, i get following output in dist/output.js:

import"./pcr.css";function t(t,e,n,r){Object.defineProperty(t,e,{get:n,set:r...

which obviously does not work in browser: Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/css". Strict MIME type checking is enforced for module scripts per HTML spec. is given for the import of pcr.css

💁 Possible Solution

not sure if my configuration is correct (was not really straightforward and took my a while to find proper settings in both parcel docs, github issues and stackoverflow), but generally, there's no reason to include CSS in browser context

🔦 Context

export an app as a ES module that can be included in a webpage

💻 Code Sample

using (s)css modules in my JS, vanJS and redux, but not any opinionated framework such as React

...
import * as cssTab from './Components/ControlPanel/Tab/styles.module.scss';
import * as cssTabItem from './Components/ControlPanel/TabMenu/Item/styles.module.scss';

import * as style from 'bundle-text:scss/cytoscape.scss';

import 'scss/index.scss';
...

🌍 Your Environment

Software Version(s)
Parcel 2.11
Node 18.17.0
npm/Yarn 9.6.7
Operating System Win11 x64

sKopheK avatar Jan 16 '24 16:01 sKopheK

  1. Don't use "module" as the target name unless you're literally building some JS library to publish to npm/.... Call it "app" or anything other than module/main/browser
  2. You imported CSS in your JS source file, so of course the Parcel output also contains the CSS import. Why don't use import the CSS in that src/index.html file?

mischnic avatar Jan 16 '24 19:01 mischnic

hi, thanks for the answer

  1. even when i had "library" there, it did the same output. the only difference was, i was able to set "outputFormat" which is disabled and auto-set for "module"
  2. as OP states, I'm using (S)CSS modules, so the imported pcr.css goes as follows:
._4EfISG_heading{letter-spacing:.0225rem;margin-top:0;margin-bottom:.625rem;font-size:1.125rem;font-weight:700}...

the only thing is the css import in the ES module really, it seems that context setting "browser" does not seem to be considered during build. when i remove the above mentioned CSS import, the result is exactly what i want

sKopheK avatar Jan 17 '24 09:01 sKopheK

@mischnic I am actually building a React library and wanted to use CSS modules so the class names don't clash with user's styles:

src/MyComponent.tsx

import { myClass } from "./MyComponent.module.css"

export function MyComponent() {
  return <div className={myClass} />
}

src/MyComponent.module.css

.myClass {
  border: 3px solid hotpink;
}

The user is supposed to import the js and css separately as described in this SO answer:

import "my-react-library/dist/style.css"
import { MyComponent } from "my-react-library"

I tried building it like that:

{
  "name": "my-react-library",
  "version": "1.0.0",
  "type": "module",
  "source": "src/MyComponent.tsx",
  "main": "dist/module.js",
  "types": "dist/types.d.ts",
  "style": "dist/style.css", // this is ignored and uses the same name as js :( but that's ok
  "scripts": {
    "prepare": "parcel build",
  },
  "devDependencies": {
    "@parcel/packager-ts": "^2.12.0",
    "@parcel/transformer-typescript-types": "^2.12.0",
    "parcel": "^2.12.0"
  }
}

This almost works but includes the css import in js. It makes sense, because they're part of the same target with one entry point and one output js file.

It would be nice if there was a way to disable it for library mode and simply not include the css import. Even better if the style key in package.json was considered a separate target which collects all the styles and ouputs a css bundle only.

phaux avatar Mar 14 '24 16:03 phaux

I also just tried similar thing without CSS modules:

src/MyComponent.tsx

export function MyComponent() {
  return <div className="myHopefullyUniqueClass" />
}

src/MyComponent.css

.myHopefullyUniqueClass {
  border: 3px solid hotpink;
}

package.json

{
  "source": "src/MyComponent.tsx",
  "main": "dist/module.js",
  "types": "dist/types.d.ts",
  "style": "dist/style.css",
  "targets": {
    "main": {},
    "types": {},
    "style": {
      "source": "src/MyComponent.css",
    }
  }
}

~~But I get an error from parcel:~~

Error: Expected content key 5777301ba3af460e to exist

Edit: nvm I cleared parcel cache and it worked. Also it doesn't work when target name is "style" but works if I change to "styles" for some reason.

phaux avatar Mar 14 '24 16:03 phaux