How does css loader interprets the #import and url() in css - javascript

How does the css-loader interprets the #import or url() in css
For exmaple if in (index.js) module if i import (Style.css)
import './Style.css';
function Component(){
//javascript code
}
My (Style.css) file if I have
body{
background:url('./image.png')
}
So, when webpack see's that import of Style.css in index.js module, How does css-loader inteprets that url() syntax of background property. will the url('./image.png') be converted to require('./image.png).
For example will
body{
background:url('./image.png')
}
converted to
body{
background:require('./image.png') //not a valid css syntax
}
Because in the documentation there is resolution example like:
url('./image.png') => require('./image.png')
So, I want to know does the whole url('./image.png') syntax is replaced by require('./image.png'). if it is the case than background with require() is not a valid css syntax.
Does interpreting url() as require() means converting it to require() or something else.

Unfortunately it's not that simple as replacing url(<>) with require(<>) in content.
css-loader first loads necessary plugins including url-parser
url-parser then collects all url(<>) occurences and generates some metadata about them
Later on when the loader javascript code is generated it wraps those things in ___CSS_LOADER_GET_URL_IMPORT___ function

Related

How to use multiple CSS modules with Tailwind in Remix.js?

I'm using Remix with Tailwind css.
currently I followed the tailwind and remix docs to add a global css file:
"scripts": {
"dev:css": "tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css -w"
}
But what if I want to have a tailwind css file for a single component? like so:
# app/components/button.css
.button-primary {
#apply bg-slate-400;
}
// app/components/Button.jsx
import './button.css'
export function Button() {
return <button className='button-primary'>My Button</button>
}
Remix doesn't throw any errors but the styles are not applied, not sure if this is related to tailwind not parsing the button.css file or remix's issue
CSS modules are not currently supported in remix, you can follow the relevant discussion in the repo: https://github.com/remix-run/remix/discussions/2214
For now, you will need to expose your component CSS using the links() function on every route that uses it.

How to publish a react-component with css modules that can be consumed by both, projects using ES Modules and CommonJs for css modules

For some frameworks (eg. Gatsby >= V3) the default for importing CSS modules is as ES modules like so:
import { class1, class2 } from 'styles.modules.css'
// or
import * as styles from 'styles.modules.css'
https://www.gatsbyjs.com/docs/reference/release-notes/migrating-from-v2-to-v3/#css-modules-are-imported-as-es-modules
Other projects such as Create React App still use the default export like this:
import styles from 'styles.modules.css'
How can I publish a react-component (that uses css modules internally) so that it can be imported and used in both scenarios without extracting the css?
One workaround I found is to generate the css module hashed classes and extract the stylesheet. Then import the stylesheet with the hashed classes instead of the css module stylesheet. Every bundler that is able to import css modules should also be able to deal with the extracted css file.
I am using babel-plugin-css-modules-transform for this using the following configuration:
…
"plugins": [
[
"css-modules-transform",
{
"extractCss": {
"dir": "./lib/",
"relativeRoot": "./src/",
"filename": "[path]/[name].compiled.css"
},
"keepImport": true,
"importPathFormatter": "./importPathFormatter"
}
]
]
…
The keepImport option will keep the import but transforms it from eg. import * as styles from 'styles.module.css' to import 'styles.module.css'.
I use this option in combination with the undocumented option importPathFormatter to import the transformed css. CSS preprocessing eg. postCSS is done by the consuming application.
Content of ./importPathFormatter.js:
module.exports = path => path.replace(/\.css$/, '.compiled.css');
In the long term I want to migrate my projects to vanilla extract and use rollup/vite for bundling, but for now this is working fine.

Import ES6 Module from local script

Lets say I import the following html file with
<link rel="import" href="somefile.html">
and the somefile.html looks like this:
<template>
<some-tags>...</some-tags>
</template>
<script type="module">
export default { some object }
</script>
Normally I would import a es6 module like so
import MyVariable from 'somefile.js'
but in this case I cannot point to the html file and I don't know how to import the module I imported through the link. Is that even possible or do I need to replace the export default with a global variable?
Module support in browsers is very new and being done in small bites. As far as I can tell from what specification we have for this so far, the only module specifiers currently supported are URLs that refer to a JavaScript resource. The export you've shown can't currently be imported. From that linked spec:
To resolve a module specifier given a script script and a JavaScript string specifier, perform the following steps. It will return either a URL record or failure.
Apply the URL parser to specifier. If the result is not failure, return the result.
If specifier does not start with the character U+002F SOLIDUS (/), the two-character sequence U+002E FULL STOP, U+002F SOLIDUS (./), or the three-character sequence U+002E FULL STOP, U+002E FULL STOP, U+002F SOLIDUS (../), return failure.
This restriction is in place so that in the future we can allow custom module loaders to give special meaning to "bare" import specifiers, like import "jquery" or import "web/crypto". For now any such imports will fail, instead of being treated as relative URLs.
Return the result of applying the URL parser to specifier with script's base URL as the base URL.
Instead, move that export into its own file and import it with a module specifier referring to the file.
You might extract the code into a another file, e.g. somefile.js :
export default {
//...
};
Then you can import that in your template:
<template>
<some-tags>...</some-tags>
</template>
<script type="module">
import somefile from "somefile.js";
//... Whatever
</script>
And in any other code... Note that you currently must use webpack or a similar system to convert your code to ES6. Javascript modules are not well supported yet.

Svelte class based component example

I'm trying to learn Svelte and TypeScript. I was wondering if there is any pattern to include or program svelte component using ES6 classes. Currently file contains all the script, html and data, css. I want to make them separate files. Please help me!
You can use a task runner to automate this. If you are using es6 classes I would recommend using rollup with rollup-plugin-svelte and rollup-plugin-buble.
I use Gulp to take the separate js, html and css files and concat them into a single file with the appropriate tags enclosing the script and styles. The combined file can be compiled then deleted.
Structure
To help keep the file files clean and easy to work with the HTML, CSS and JavaScript can be seperate.
src/hello/hello.css
.message {
font-size: 10pt;
}
src/hello/hello.html
<div class="message">{{message}}</div>
src/hello/hello.js
export default {
data: function () {
return {
message: 'Hello, world!'
}
}
}
Combine
Svelte requires that components be just a single html file, so the three separate files need to be combined into a single file. Since this file is HTML, the JavaScript must be wrapped in tags and the CSS must be wrapped in tags.
src/hello/hello.temp.html
<style>
.message {
font-size: 10pt;
}
</style>
<div class="message">{{message}}</div>
<script>
export default {
data: function () {
return {
message: 'Hello, world!'
}
}
}
</script>
Compile
The temp file can be compiled using svelte or rollup with the svelte plugin then deleted.
[Edit]
Here is a gist with a gulp file showing how this works.
Link here
[Edit 2]
There is a Yeoman generator to set this all up for you, here is a link to the npm package.
generator-svelte-workbench

Electron and Typescript: How do I handle modules at runtime correctly?

I'm writing an Electron desktop application in Typescript. After compilation, the project organization looks something like this:
dist
html
index.html
scripts
ApplicationView.js
ApplicationViewModel.js
In index.html I have this script tag:
<script src="../scripts/Application.js"></script>
All my files are compiled from Typescript to ES2015 (targeting ES6 and using ES6 modules) and transpiled by Babel to ES5. ApplicationView.ts looks like this:
///<reference path="../../typings/main.d.ts" />
import * as $ from "jquery";
import * as ko from "knockout";
import ApplicationViewModel from "./ApplicationViewModel";
$(document).ready(() => {
ko.applyBindings(new ApplicationViewModel("Hello!"));
});
Here's the contents of ApplicationViewModel.ts:
import * as ko from "knockout";
export default class ApplicationViewModel {
public greeting: KnockoutObservable<string>;
constructor(greeting: string) {
this.greeting = ko.observable(greeting);
}
}
Electron throws an error saying it can't find the module ./ApplicationViewModel. However, in the debugger console, I can successfully import the module with:
require("../scripts/ApplicationViewModel");
So, what's wrong is obvious. The script tag effectively copies the contents of Application.js into the HTML file, changing the context for the module's relative path. My question is what should I really be doing?
I've seen the use of require.js in the script tag. But Electron runs on Node.js. If this is the right way to handle my problem, why then would I need another module loader? How would I make sure the two play nice?
Figured it out. Pretty simple actually. I replaced the <script> tag in the HTML file with this:
<script>
require("../scripts/ApplicationView");
</script>
Works like a charm! Now I just need to figure out why JQuery isn't working properly...
You are mixing up the es5 and the es6 ways to export modules:
module.exports = ApplicationViewModel; // ES5
export default ApplicationViewModel; // ES6

Categories

Resources