Why CSS loader of webpack not working? - reactjs

I am making the toy example described in the documentation of css-loader:
https://github.com/webpack-contrib/css-loader
I also tried this basic guide that suggest the same: https://css-tricks.com/css-modules-part-2-getting-started/
However, both VS Code highlight and when bundling through the command line complain that the module of the CSS file is not available. Like it does not really recognize it. I have checked I indeed really have installed css-loader, webpack etc. Other than the css loader, webpack is working fine for javascript, typescript etc. So it is really just a problem with CSS. Any ideas why failing?
The error I get is:
TS2307: Cannot find module 'styles.css'.
My file:
import test from 'styles.css';
I tried also without file extension, with and without curly braces etc. But really followed the toy example in the docu of css-loader.
My webpack.config file:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const config = {
entry: "./src/index.tsx",
resolve: {
extensions: ['.tsx', '.js', '.css']
},
output: {
filename: "bundle.js",
},
plugins: [
new HtmlWebpackPlugin({
title: 'title Cool!',
}),
],
module: {
rules: [
{
test: /.tsx$/,
loader: "ts-loader" ,
},
{
test: /.css$/,
use: [ 'style-loader', 'css-loader' ],
}
]
}
}
module.exports = config;
Any ideas?

Are you sure you need a named import? This should work: import './styles.css';.

The problem was related to typescript and not to webpack or the css loader.
So I needed to add css files to modules for typescript:
declare module '*.css' {
const content: any;
export default content;
}
Did the trick. No clue why this is not mention in any of the dozens of tutorial and guides I saw.

You should provide a relative path to your file:
import test from './path/to/styles.css';

Related

How to use google fonts in manually created React app?

I created React app manually (not create-react-app) one by one such as index.js, App.js, index.css, components folder etc because I am using React app as a separate app in the Django project.
And in order to use google fonts, I followed this answer.
But when I write #import url('https://fonts.googleapis.com/css?family=Josefin+Sans') in the index.css, it is giving me this error.
ERROR in ./src/index.css 1:0
Module parse failed: Unexpected character '#' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> #import url('https://fonts.googleapis.com/css?family=Josefin+Sans');
|
# ./src/index.js 4:0-21
webpack 5.15.0 compiled with 1 error in 999 ms
I think this error is related to webpack.config.js and it seems I need to add some rules in the module section related to css-loader, file-loader, or something else, but I am not sure how to write.
This is just my thought, I have no idea why this is happening.
webpack.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "./static/frontend"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
},
optimization: {
minimize: true,
},
plugins: [
new webpack.DefinePlugin({
"process.env" : {
NODE_ENV: JSON.stringify("production"),
}
})
]
};
How to solve this issue? (This issue has happened when I tried to use react-toastify also. So I removed it and used another alternative package.) How to use fonts in the non create-react-app based project?

mini-css-extract-plugin: Import CSS files ONLY when importing JS files

I'm making a tree shaken component library in React with webpack#5.24.2 and mini-css-extract-plugin#1.3.9 that has to work for client side rendering and server side rendering. I want to be able to do the following, create "N" components in the library, each with their specific "SCSS" files, something like this:
// KhalComponent.tsx
import React from 'react';
import './KhalComponent.scss';
const KhalComponent = () => {
return <div className="khal-component">Khal Component</div>;
};
export default KhalComponent;
// KhalComponent.scss
.khal-component {
padding: 2rem;
background: red;
}
and when an external project does the following:
import KhalComponent from 'some-library/KhalComponent' it gets the component along with its styles. I have this working with style-loader but I've read that this isn't a correct configuration for production AND it DOESN'T work with SSR (using NextJS) since with style-loader it tries to inject the styles adding them with document.createElement (document doesn't exist in the server side). So I tried migrating to using mini-css-extract-plugin to achieve this client side AND server side. I see that mini-css-extract-plugin does create the separate CSS files but (as far as I can tell) it doesn't let the corresponding JS file (KhalComponent.js) know that it NEEDS to load the CSS whenever KhalComponent is imported in another project.
I'm not generating an HTML file in this external component library since its just to import components JS and CSS content.
The webpack config is the following:
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const entries = require('./entries');
const LIB_NAME = 'lib';
module.exports = {
entry: entries,
output: {
filename: '[name].js',
path: path.resolve(__dirname, LIB_NAME),
},
plugins: [new CleanWebpackPlugin(), new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.s?css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
],
},
externals: [
{
react: 'react',
'react-dom': 'react-dom',
},
],
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
devtool: 'source-map',
devServer: {
contentBase: './lib',
hot: true,
},
};
and entries.js is:
const path = require('path');
const SRC_DIR = path.resolve('src');
module.exports = {
// Components
KhalComponent: path.join(SRC_DIR, 'KhalComponent'),
LinkComponent: path.join(SRC_DIR, 'LinkComponent'),
};
What am I missing or what tools should I use to do this? Thank you very much in advance!
I did a lot of research for this and the best solution I came up with was to just use mini-css-extract-plugin to separate out the css bundle (as I want to give user the functionality to add custom css in the form of styles) and port all imports through a parent index.js file.
Directory would look something like this:
|-build/
|--main.min.js
|--main.min.css
|-index.js
And your index.js content would look something like this:
export {default} from './build/main.min.js';
export * from './build/main.min.js';
import './index.css';
Hope it helps...

How to use plugin to reduce size when import lodash

Here is my code : import _ from 'lodash';
I want to use babel-plugin-transform-imports to reduce size of folder when "yarn build".
But I don't know how to set up plugin and config in wepack.config.js
Thank you so much
There is three way to reduce:
1. When in development, you can include the folder where you are going to compile by config the loaders, so the file outside this folder won't be compiled. Loader config are like the following code:
{
test: /\.(js|mjs|jsx)$/,
include: path.resolve(__dirname,"src"),//important
use: {
loader: 'babel-loader'
}
}
2、 You can use DDL to pre-compile the third-party library.
e.g.
Firstly create vendor.js, that is to say you need to bundle it by another webpack config.
const webpack = require('webpack')
const library = '[name]_lib'
const path = require('path')
module.exports = {
mode:"production",
entry: {
vendors: ['lodash']
},
output: {
filename: '[name].dll.js',
path: path.join(__dirname,"dist/vendor"),
library
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'dist/[name]-manifest.json'),
// This must match the output.library option above
name: library
}),
]
}
And then you need to include mainfest.json in your project webpack config:
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: path.join(__dirname, 'dist/vendors-manifest.json'),
})
]
3、 You can use externals to exclude it, you can config it like:
externals : {
lodash : {
commonjs: 'lodash',
amd: 'lodash',
root: '_' // indicates global variable
}
}
And don't forget to include lodsh script in HTML, because webpack don't compile or include it in your bundle. If you don't include ,the broswer will throw an error.
You can check more usage at Webpack website:
https://webpack.js.org/configuration/externals/
https://webpack.js.org/plugins/dll-plugin/

Import line getting error in Firefox

I have a React project that uses OverlayLoader library. Although code runs just fine on Chrome, it gets "TypeError: can't convert null to object" in firefox. After taking some time tracking down the error, I found that it comes from import line where I import OverlayLoader library
import OverlayLoader from 'react-overlay-loading/lib/OverlayLoader';
There's also "Source map error: request failed with status 404". But that shouldn't matter though. Why this error only occurs in Firefox?
EDIT : This is content of webpack.config.js
var dotenv = require('dotenv').config({path: __dirname + 'path'});
var webpack = require('webpack');
module.exports = {
entry: ["./js/app.jsx", "./css/custom.scss", "./css/main.scss"],
output: {
path: "public/js",
publicPath: "/js",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.jsx?|\.js$/,
exclude: /(node_modules|bower_components|neal-react)/,
loader: "babel-loader",
},
{
test: /\.scss$/,
loader: "style!css!sass"
}
]
},
resolve: {
alias: {
querystring: 'querystring-browser'
}
},
plugins: [
new webpack.DefinePlugin({
"process.env": dotenv.parsed
})
]
};
Two things you can check:
Do you have a libraryTarget in your webpack config? If you, could you try and remove that?
Are you using externals in your webpack configuration? If so, the package will not be bundles and the browser might not have access to it.
Hope it helps.
EDIT:
Seems like it's a source-map issue. I thought that it might be in your configuration but it isn't. Usually a source-map error is because the browser can't find the source-map I think this is an issue you can report with the repo. It's not your configuration.

angular 2 web worker Uncaught SyntaxError: Unexpected token import [duplicate]

I'm trying to move the whole execution of an Angular 2 app to a web worker, but I've find out that all examples available right now are using System.js, and I'm trying to do so with a WebPack based project (built with angular-cli).
Has anyone done this or have an idea on how to do this with WebPack?
Below is my main.ts bootstrap file:
import './polyfills.ts';
import { enableProdMode } from '#angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
import {bootstrapWorkerUi} from '#angular/platform-webworker';
bootstrapWorkerUi('/app/loader.js');
My loader.js looks like this:
import {platformWorkerAppDynamic} from '#angular/platform-webworker-dynamic';
import { AppModule } from './app/';
platformWorkerAppDynamic().bootstrapModule(AppModule);
And my app.module.tsis declaring #NgModulethis way:
import { NgModule } from '#angular/core';
import {WorkerAppModule} from '#angular/platform-webworker';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
WorkerAppModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
However, when I run it, I get the error Uncaught SyntaxError: Unexpected token import in loader.js:1.
The issue seems related with webpack and some lack of imports of #angular libs in the webworker side, as suggested by Tamas Gegedus and MathMate, so the next step is to modify the webpack config file in order to provide all the required libs to the webworker. I'll work on that.
-----------
UPDATE
-----------
Since angular-cli do not provide access to webpack.config.js file, I've included mine, making little changes in code so it can work. I created the second entry point at webpack config file and I'm getting the error VM33:106 Uncaught ReferenceError: window is not defined.
Webpack config file looks like this:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var helpers = require('./config/helpers');
module.exports = {
entry: {
'app': ['./src/polyfills.ts', './src/vendor.ts', './src/main.ts'],
'webworker': ['./src/workerLoader.ts']
},
resolve: {
extensions: ['', '.ts', '.js']
},
output: {
path: helpers.root('dist'),
publicPath: 'http://localhost:8080/',
filename: '[name].js'
},
devtool: 'cheap-module-eval-source-map',
module: {
loaders: [
{
test: /\.ts$/,
loaders: ['awesome-typescript-loader?tsconfig=./src/tsconfig.json', 'angular2-template-loader']
},
{
test: /\.html$/,
loader: 'html'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file?name=assets/[name].[hash].[ext]'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
excludeChunks: ['webworker']
}),
new ExtractTextPlugin('[name].css')
]
};
where polyfills.ts and vendor.ts include polyfills and angular libs respectively.
I've created 2 entry points, that generate 2 outputs (app.js and webworker.js).
With the HtmlWebpackPlugin, the first one is included in the index.html file, but not the second one.
When index.html is included, main.ts (contained in app.js) is called and tries to bootstrap the webworker using the second output of webpack (webworker.js):
import {bootstrapWorkerUi} from '#angular/platform-webworker';
bootstrapWorkerUi('../webworker.js');
webworker.js has been generated by webpack using workerLoader.ts entry, that is like previous loader.js, but including some imports.
WorkerLoader.ts file looks like this:
import './polyfills.ts';
import '#angular/core';
import '#angular/common';
import {platformWorkerAppDynamic} from '#angular/platform-webworker-dynamic';
import { AppModule } from './app/';
platformWorkerAppDynamic().bootstrapModule(AppModule);
I know that the web worker is been generated, as shown in the following image, but as shown in the image, I get the error VM33:106 Uncaught ReferenceError: window is not defined, and nothing is displayed except the Loading message from index.html.
On the other side, I think that the webpack config is OK because if running the app with webpack in NO webworker mode, it works fine.
Right now I think that this issue is related with webworker bootstrap, but I'm quite stucked here.
Any help would be appreciated ;)
I finally solved the issue :)
NOTE: if you have generated the project using Angular CLI 1.0 or higher, you can now use their own webpack config file, and that simplifies the whole process. Check this answer in that case.
After running the code with my custom webpack config, I realized that the error VM33:106 Uncaught ReferenceError: window is not defined was caused by webpack-dev-server.
I solved it by:
1 - doing a standalone webpack build
$: webpack --watch #this creates the bundes at myProject/dist
and
2 - running with another devserver tool like simplehttpserver
$: npm install simplehttpserver -g
$: simplehttpserver -p 8080 dist/ #as my webpack bundle is included in index.html using that port by default
And voilà, the error is gone and it simply works!
 
Changes applied to angular-cli project: Webpack config
Let me summarize the webpack changes regarding the original Angular-CLI project.
As angular-cli do not provide access to webpack.config.js file and customizing webpack is key to use webworkers, I've included mine, making little changes in code.
Webpack config file looks like this:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var helpers = require('./config/helpers');
module.exports = {
entry: {
'app': ['./src/polyfills.ts', './src/vendor.ts', './src/main.ts'],
'webworker': ['./src/workerLoader.ts']
},
resolve: {
extensions: ['', '.ts', '.js']
},
output: {
path: helpers.root('dist'),
publicPath: 'http://localhost:8080/',
filename: '[name].js'
},
devtool: 'cheap-module-eval-source-map',
module: {
loaders: [
{
test: /\.ts$/,
loaders: ['awesome-typescript-loader?tsconfig=./src/tsconfig.json', 'angular2-template-loader']
},
{
test: /\.html$/,
loader: 'html'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file?name=assets/[name].[hash].[ext]'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
excludeChunks: ['webworker']
}),
new ExtractTextPlugin('[name].css')
]
};
where polyfills.ts and vendor.ts include polyfills and angular libs respectively.
I've created 2 entry points, that generate 2 outputs (app.js and webworker.js).
With the HtmlWebpackPlugin, the first one is included in the index.html file, but not the second one.
When index.html is included, main.ts (contained in app.js) is called and bootstraps the webworker like this:
import {bootstrapWorkerUi} from '#angular/platform-webworker';
bootstrapWorkerUi('../webworker.js');
webworker.js is the code webpack generated using workerLoader.ts entry.
WorkerLoader.ts file looks like this:
import './polyfills.ts';
import '#angular/core';
import '#angular/common';
import {platformWorkerAppDynamic} from '#angular/platform-webworker-dynamic';
import { AppModule } from './app/';
platformWorkerAppDynamic().bootstrapModule(AppModule);
And AppModule looks like this:
import { NgModule } from '#angular/core';
import {WorkerAppModule} from '#angular/platform-webworker';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
WorkerAppModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Code example
To make easier to understand the differences, I've created a project showing how to convert a regular angular 2 project in a web workers based one. Check this repo: https://github.com/kaikcreator/webWorkerFactorialExample
You'll see in master branch the "single thread" code, and in webWorkers branch, the changes to run code using web workers.
As Tamas Hegedus has already mentioned in comment, most likely your webpack bundle is still referring es6 file for loader.js.
You need to create separate bundle with entry point for loader script.
If you share your webpack config then it would be easier to tell where the things might be going wrong.
Also your loader script needs to have required polyfills. You can add
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';

Resources