CSS/SCSS Code module not found in VSCode using relative path - css

I'm writing a SharePoint Framework web-part in VS Code.
Unfortunately my scss styles file cannot be found, even though it's in the same path - please see the image below:
I also checked the styles file Events.module.scss in case an error in their was preventing it being imported, but there are no issues with that file...
I have tried restarting VS Code...tried moving the files around, tried renaming the scss file...
So what is missing here, and how can I resolve it?

I found the solution at How to use CSS Modules with TypeScript and webpack
Either we can bypass the import by using const s = require('./Button.css');
or, install Typings for CSS Modules like so:
npm install --save-dev typings-for-css-modules-loader
then add the new rule to webpack.config:
module: {
rules: [
{
test: /\.css$/,
include: path.join(__dirname, 'src/components'),
use: [
'style-loader',
{
loader: 'typings-for-css-modules-loader',
options: {
modules: true,
namedExport: true
}
}
]
}
]
}
it's a bit of a faff or kerfuffle but it is possible

Related

How to handle css modules with ?module suffix in Jest

I'm building a react app that mixes global css with css modules using Symfony's webpack encore. To avoid global CSS issues I've settled on using import 'app.css' for global styles and import styles from 'component.css?module' in my components. This is working as expected, however Jest is not pruning the ?module from the css module import and cannot find the file, giving me errors like Cannot find module './login.module.css?module' from 'assets/pages/Login/index.jsx'.
Does anyone know how to workaround this?
I managed to fix this myself. If anyone is interested, I enabled css modules in webpack.config.js by adding
.configureCssLoader((options) => {
options.modules = true;
})
However this then applies css module loading to all .css files and breaks global css rules.
So I modified the webpack config manually using the following at the end of webpack.config.js
const config = Encore.getWebpackConfig();
// only include files ending in module.css in the module css loader
config.module.rules[1].include = /\.module\.css$/;
// add another css loader without modules enabled to parse global css files
config.module.rules.push({
test: /\.css$/,
use: ["style-loader", "css-loader"],
exclude: /\.module\.css$/,
});
module.exports = config;
Not sure if this is the best way, but seems to be working ok at the moment!
I had some similar issue and fixed it with something like that (with Webpack Encore) :
.configureCssLoader(options => {
options.modules = {
auto: /\.module\.\w+$/i
}})
And now you can create a file with '.module.scss' suffix, and you can import it in a ts file. (working with jest, unlike ?module)

Electron Forge with SASS

I use Electron Forge for an Electron app. I also make use of React and TypeScript, and I would also like to use SASS, but my current attempts fail. Apparently SASS already works without adding any new dependency to the package.json, as electron-compile takes care of that. That's what it sais on electronforge.io under Develop.
I tried adding the style.scss as an import within the first TypeScript class app.tsx, but after adding this compiling does not work anymore:
import "./style/style.scss";
leads to:
[24717:0221/194746.779571:ERROR:CONSOLE(7830)] "Extension server error: Object not found: <top>", source: chrome-devtools://devtools/bundled/shell.js (7830)
I also tried to put a link element into the head element in the index.html, but this does not do the trick either. Compiling works, but no CSS works are done:
<link rel="stylesheet" href="style/style.scss">
also tried:
<link rel="stylesheet" type="text/css" href="style/style.scss">
and:
<link rel="stylesheet" type="text/scss" href="style/style.scss">
and:
<link rel="stylesheet" type="text/sass" href="style/style.scss">
The 'style.scss` file:
body {
background-color: #ff0000;
color: #0000ff;
}
But none of them work. What must I do to make use of SASS files within Electron Forge?
I've managed to get this working, little bit late but hopefully this helps someone in the future. On an example app using webpack (as I'm pretty sure this is required), Electron Forge generates some js files in the root directory for webpack config.
yarn create electron-app my-new-app --template=webpack
or
yarn create electron-app my-new-app --template=typescript,webpack
https://www.electronforge.io/templates/typescript-+-webpack-template
Following this, there's two files in the project root, webpack.rules.js and webpack.plugins.main.config.js. These need to be modified to work properly, and you need to install sass-loader as a dev dependency. node-sass was recently deprecated so sass-loader will handle that okay.
Your webpack.plugins.main.config.js file should include:
module: {
rules: require("./webpack.rules"),
},
resolve: {
extensions: [
".js",
".ts",
".jsx",
".tsx",
".css",
".json",
".scss",
".sass",
],
},
Additionally, your webpack.rules.js file should have a new rule added:
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
"style-loader",
// Translates CSS into CommonJS
"css-loader",
// Compiles Sass to CSS
"sass-loader",
],
},
This is what's provided in the documentation on the page for sass-loader, properly implemented into electron forge. https://www.npmjs.com/package/sass-loader
Finally, your renderer.js (or renderer.js) should be adapted to import a scss file rather than a css file.
import './index.scss';
From there, you should be good to go!
You need to compile the SASS file to generate a CSS file and then put it in the index.html
Yo can use the console to try it
# Path to SASS File > OUTPUT path to CSS File
sass style/sass/style.scss style/style.css
then, import the file in the head
<link rel="stylesheet" href="style/style.css">

with webpack, why should one import CSS files from JS source code and not build CSS in isolation like the tradition did?

webpack doc for loading css:
https://webpack.js.org/guides/asset-management/#loading-css1
The webpack doc asks to import the CSS files from the Javascript code and to then run extract-text-webpack-plugin to extract the CSS.
--> with webpack, why should one import CSS files from JS source code and not build CSS in isolation like the tradition did?
By not importing CSS from Javascript, I mean that the webpack config for CSS has no ".js" extension, and it parses the CSS/SCSS files directly.
There are benefits of not importing CSS from javascript:
(objective fact). If one wants to build only CSS, it will be faster if the bundler does not need to parse the Javascript source code. Besides, one can run the bundlers for CSS and Javscript in parallel by using parallel-webpack.
(subjective, based on tradition, but most important in my opinion). SASS building in isolation has been the tradition for years. Therefore, we can achieve better HTML semantics and maintainability. Importing CSS from JS is virtual and may lead to neglect the generated separate CSS bundle.
(objective fact) One can split more the config files for CSS and Javascript, for more clarity.
I'm more a traditionalist than most as i've been doing this for over 15 years, but I would say the new way to separate concerns is better than the traditional way.
In the old thinking we use to separate layout from styling from functionality (html from css from js). This is more 'vertical' and made knowing where files are easy, but made finding specific code to do with 'features' hard. I.e. a button might be made up of a small button section within /src/shop-front.html, a few lines of code within /src/css/shop-front.css and then the enhanced functionality would live somewhere in /src/js/shop-front.js
The new way of thinking is to separate concerns by components. So now you would have your shop-front, but this would be made from /src/components/button/ and all files will live in the same place. Including the js file which includes the css as mentioned.
The benefit being, if you decide to swap button for fancy-button all you do is change the shop-front import button from 'button' to import button from 'fancy-button'. all old code will be removed automatically. no need to try to digest and change code in multiple places.
To address your concerns:
true, node-sass is fast, but I would say the difference between that and going via webpack is negligible and the improvement in dev experience (as mentioned above) is worth any extra ms
This point does apply as the way the css/sass is built does not change just because we require it from a js file. I guess you mean if you were to use css modules, but this is a choice, you don't have to. I use sass and apply class names as i would normally.
In webpack config, you could split the js config from the css config if you wanted to. I wouldn't argue that this would make things any clearer though. the config is so small, it's not worth worrying about.
My folder structure is nice and easy to reason with:
This is a basic config for simple scss imports
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { SRC, DIST } = require('./src/config/paths');
module.exports = {
devtool: 'source-map',
cache: true,
context: SRC,
entry: {
app: [`${SRC}/client-entry.js`]
},
output: {
path: DIST,
filename: '[name]-[chunkhash].js',
publicPath: '/'
},
plugins: [
new ExtractTextPlugin('[name]-[contenthash].css'),
],
resolve: {
modules: ['node_modules', SRC],
extensions: ['.js', '.jsx', '.scss']
},
module: {
rules: [
{
test: /\.jsx?$/,
include: [/src/],
loader: 'babel-loader',
options: {
cacheDirectory: true
}
},
{
test: /\.s?css$/,
include: [/src/],
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', 'sass-loader']
})
}
]
}
};

Webpack and Sass correctly processes background: url() image but then it's not found when used with webpack-dev-server

I am using Webpack 2 and webpack-dev-server together with Sass loader, actual configuration:
{
test: /\.scss/,
loaders: [
"style",
{ loader: "css", query: { modules: false, sourceMap: true } },
{ loader: "resolve-url" },
{ loader: "sass", query: { sourceMap: true } }
]
}
This works quite well and the image referenced in background: url() is processed by webpack and also replaced in the style for something like background-somehash.jpg, this file can be accessed by typing http://localhost:8080/background-somehash.jpg. It also works when I provide whole url (including localhost) in a style background definition using developer tools...
The only thing that don't work is the original css produced by webpack which looks like background: url(background-somehash.jpg). I also tried various urls like ./, ../, ../../ or ./images/ to try out if root was set somehow differently. What I don't get is that the file is readily available at the root...
EDIT:
When used together with extract-text-webpack-plugin which extracts styles into separate real styles.css file it works just fine. The question is why it doesn't work when final css is being served from javascript bundle ?
CLARIFICATION:
Everything is referenced correctly, the image is available, it all works when I extract css into separate file using extract-text-webpack-plugin it just doesn't work when the completely same css is served from bundle.js which is then referenced in the index.html like <link href="blob:..." rel="stylesheet">
Things you should check:
Is the referenced image recognized by webpack?
Just delete the image and check if the webpack build fails. If that's the case, it is not an issue with your loader configuration.
Check the requested URL with your browser developer tools
If the request is terminated with a 404:
Check if output.publicPath (webpack) / contentBase (webpack-dev-server) point to the same location. This is from the browser's perspective (=no absolute file paths)
If you're using a <base>-tag, you need to ensure that it does replace the base URL correctly.

Webpack "OTS parsing error" loading fonts

My webpack config specifies that fonts should be loaded using url-loader, and when I try to view the page using Chrome I get the following error:
OTS parsing error: invalid version tag
Failed to decode downloaded font: [My local URL]
The relevant parts of my config look like this:
{
module: {
loaders: [
// ...
{
test: /\.scss$/,
loaders: ['style', 'css?sourceMap', 'autoprefixer', 'sass?sourceMap'],
},
{
test: /images\/.*\.(png|jpg|svg|gif)$/,
loader: 'url-loader?limit=10000&name="[name]-[hash].[ext]"',
},
{
test: /fonts\/.*\.(woff|woff2|eot|ttf|svg)$/,
loader: 'file-loader?name="[name]-[hash].[ext]"',
}
],
},
}
It doesn't happen in Safari, and I haven't tried Firefox.
In development I'm serving files through webpack-dev-server, in production they're written to disk and copied to S3; in both cases I get the same behaviour in Chrome.
This also happens to larger images (greater than the 10kB limit in the image loader config).
TL;DR Use absolute paths to your assets (including your complete hostname) by setting your output.publicPath to e.g. "http://example.com/assets/".
The problem
The problem is the way that URLs are resolved by Chrome when they're parsed from a dynamically loaded CSS blob.
When you load the page, the browser loads your Webpack bundle entry JavaScript file, which (when you're using the style-loader) also contains a Base64 encoded copy of your CSS, which gets loaded into the page.
This is what it looks like in Chrome DevTools
That's fine for all the images or fonts which are encoded into the CSS as data URIs (i.e. the content of the file is embedded in the CSS), but for assets referenced by URL, the browser has to find and fetch the file.
Now by default the file-loader (which url-loader delegates to for large files) will use relative URLs to reference assets - and that's the problem!
These are the URLs generated by file-loader by default - relative URLs
When you use relative URLs, Chrome will resolve them relative to the containing CSS file. Ordinarily that's fine, but in this case the containing file is at blob://... and any relative URLs are referenced the same way. The end result is that Chrome attempts to load them from the parent HTML file, and ends up trying to parse the HTML file as the content of the font, which obviously won't work.
The Solution
Force the file-loader to use absolute paths including the protocol ("http" or "https").
Change your webpack config to include something equivalent to:
{
output: {
publicPath: "http://localhost:8080/", // Development Server
// publicPath: "http://example.com/", // Production Server
}
}
Now the URLs that it generates will look like this:
Absolute URLs!
These URLs will be correctly parsed by Chrome and every other browser.
Using extract-text-webpack-plugin
It's worth noting that if you're extracting your CSS to a separate file, you won't have this problem because your CSS will be in a proper file and URLs will be correctly resolved.
For me the problem was my regex expression. The below did the trick to get bootstrap working:
{
test: /\.(woff|ttf|eot|svg)(\?v=[a-z0-9]\.[a-z0-9]\.[a-z0-9])?$/,
loader: 'url-loader?limit=100000'
},
As asnwered here by #mcortesi if you remove the sourceMaps from the css loader query the css will be built without use of blob and the data urls will be parsed fine
As with #user3006381 above, my issue was not just relative URLs but that webpack was placing the files as if they were javascript files. Their contents were all basically:
module.exports = __webpack_public_path__ + "7410dd7fd1616d9a61625679285ff5d4.eot";
in the fonts directory instead of the real fonts and the font files were in the output folder under hash codes. To fix this, I had to change the test on my url-loader (in my case my image processor) to not load the fonts folder. I still had to set output.publicPath in webpack.config.js as #will-madden notes in his excellent answer.
I experienced the same problem, but for different reasons.
After Will Madden's solution didn't help, I tried every alternative fix I could find via the Intertubes - also to no avail. Exploring further, I just happened to open up one of the font files at issue. The original content of the file had somehow been overwritten by Webpack to include some kind of configuration info, likely from previous tinkering with the file-loader. I replaced the corrupted files with the originals, and voilĂ , the errors disappeared (for both Chrome and Firefox).
I know this doesn't answer OPs exact question but I came here with the same symptom but a different cause:
I had the .scss files of Slick Slider included like this:
#import "../../../node_modules/slick-carousel/slick/slick.scss";
On closer inspection it turned out that the it was trying to load the font from an invalid location (<host>/assets/css/fonts/slick.woff), the way it was referenced from the stylesheet.
I ended up simply copying the /font/ to my assets/css/ and the issue was resolved for me.
Since you use url-loader:
The url-loader works like the file-loader, but can return a DataURL if the file is smaller than a byte limit.
So another solution to this problem would be making the limit higher enough that the font files are included as DataURL, for example to 100000 which are more or less 100Kb:
{
module: {
loaders: [
// ...
{
test: /\.scss$/,
loaders: ['style', 'css?sourceMap', 'autoprefixer', 'sass?sourceMap'],
},
{
test: /images\/.*\.(png|jpg|svg|gif)$/,
loader: 'url-loader?limit=10000&name="[name]-[hash].[ext]"',
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=application/font-woff',
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=application/font-woff',
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=application/octet-stream',
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader',
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=image/svg+xml',
},
],
},
}
Allways taking into account on what the limit number represents:
Byte limit to inline files as Data URL
This way you don't need to specify the whole URL of the assets. Which can be difficult when you want Webpack to not only respond from localhost.
Just one last consideration, this configuration is NOT RECOMMENDED for production. This is just for development easiness.
The best and easiest method is to base64 encode the font file. And use it in font-face.
For encoding, go to the folder having the font-file and use the command in terminal:
base64 Roboto.ttf > basecodedtext.txt
You will get an output file named basecodedtext.txt. Open that file. Remove any white spaces in that.
Copy that code and add the following line to the CSS file:
#font-face {
font-family: "font-name";
src: url(data:application/x-font-woff;charset=utf-8;base64,<<paste your code here>>) format('woff');
}
Then you can use the font-family: "font-name" in your CSS.
I just had the same issue with Font Awesome. Turned out this was
caused by a problem with FTP. The file was uploaded as text (ASCII)
instead of binary, which corrupted the file. I simply changed my FTP
software to binary, re-uploaded the font files, and then it all
worked.
https://css-tricks.com/forums/topic/custom-fonts-returns-failed-to-decode-downloaded-font/
this helped me in the end
I had the same issue with FTP transferring files as text
If you're using Angular you need to check to make sure your
<base href="/">
tag comes before your style sheet bundle. I switched my code from this:
<script src="~/bundles/style.bundle.js"></script>
<base href="~/" />
to this:
<base href="~/" />
<script src="~/bundles/style.bundle.js"></script>
and the problem was fixed.
Thanks to this post for opening my eyes.
As of 2018,
use MiniCssExtractPlugin
for Webpack(> 4.0) will solve this problem.
https://github.com/webpack-contrib/mini-css-extract-plugin
Using extract-text-webpack-plugin in the accepted answer is NOT recommended for Webpack 4.0+.
The limit was the clue for my code, but I had to specify it like this:
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
},
},
],
In my case adding following lines to lambda.js {my deployed is on AWS Lambda} fixed the issue.
'font/opentype',
'font/sfnt',
'font/ttf',
'font/woff',
'font/woff2'
Had same problem like #adam-mccormick and user3006381. I am using webpack5 and hot module.
My .eot or .woff files contained:
export default __webpack_public_path__ + "./fonts/montserrat-v24-latin-ext-regular.woff2";
and my webpack.config.js looked like:
modules.exports = {
//...
module: {
rules: [
//...
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
use: [{
loader: "file-loader",
options: {
name: './fonts/[name].[ext]',
}
}]
}
]
}
}
and this was my problem solution:
modules.exports = {
//...
module: {
rules: [
//...
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: './fonts/[name].[ext]',
}
}
]
}
}

Resources