I'm running an isomorphic app using React and webpack which all works great. One thing I'm struggling to handle though is the preloading of css before rendering components.
I've been trying to import my sass file (so webpack can sass=>css) using
require('sass/app);
however this is still only applied once the client has been loaded.
The only way I can seem to avoid this is using a good old stylesheet linked in , which means I'll lose out on all of webpack's goodies for css.
Use the Webpack ExtractTextPlugin to generate your external stylesheet from the require'd styles in your app!
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
module: {
loaders: [
{ test: /\.scss$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader", "sass-loader") }
]
},
plugins: [
new ExtractTextPlugin("styles.css")
]
}
example is adapted from the source github page
Related
I'm converting normal react app to next js,
previously I just imported scss file using
import from '.componentName.scss'
But now I have to import using
import style from 'componentName.module.scss
therefore I have to change lot of code since this is previously completed project,
is there any way to configure nexjs that allow to import scss as before
I have no idea if it'll work but you can use https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config to create a custom webpack config in nextjs. Along with that you can define a rule for styles.
...
rules: [
{
test: /\.s?css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
},
'sass-loader',
],
include: /\.s?css$/
},
],
Using that I'm pretty sure you should be able to override the way it's searching for *.module files and including them in the css bundle.
Note don't just copy that code directly, make sure it'll actually work and configure it to your needs, it's just for frame of reference.
I'm developing a react UI component and it depends on another UI component (react-widgets/lib/DropDownlist). This javascript module has resources that end with these file extensions: *.gif, *.eot, *.svg, *.woff, *.ttf.
Webpack4 is complaining that it doesn't know how to process these file types and that I might need a loader to handle these file type. One error is:
Error in .../react-widgets/dist/fonts/rw-widgets.svg?v=4.1.0
Module parse failed: ...
**You may need an appropriate loader to handle this file type.**
So I need to update my webpack.config.js file with the appropriate loaders for those file types. My config is based off of this. Side Note: A
shout out goes to Mark England who wrote this article which does a fantastic job for how to create a reusable component.
The relevant snippet is:
// Snippet from Mark's code webpack.config.js
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
I know what the syntax for webpack is to define the loaders but I don't know what loaders to use. But this sample webpack config file didn't include support for these other file types.
What have I done to try and solve the problem
I generally use create-react-app so I avoid this problem altogether. :-) It, however, doesn't allow me to create react libraries for distribution (AFAIK).
First I searched on the net webpack *.gif loader. Nothing useful.
Next I searched for webpack loaders based on file type. This gave some good results that describe the loader syntax, pointed me to some loaders file-loader and how to use them, and this question on SO that helps me realize the *.svg loader might be what I need to load svg files.
{test: /\.svg$/, use: "svg-inline-loader"},
So I might be able to use svg-inline-loader for the *.svg files.
I can repeat this approach for all of the file types.
The next approach is to examine Create React App (CRA)
I primarily develop in react, and look at the CRA webpack config files (because the create-react-app appears to stay leading edge on these topic). So I can see the url-loader is used for images (based on what the node_modules/react-scripts/config/webpack.config.dev.js file is using).
Another one down...
My question
Does webpack (or another website) have a table that lists the loaders available for given file types?
For example,
know good image loaders for the following file types are:
Webpack 4
*.gif, *.jpg => url-loader
*.svg => svg-inline-loader
*.eot => ???
I realize that because webpack is more of a plugin/loader architecture that it might not be webpacks place to have this list so another website might need to have it.
When you need a loader what do you do?
If there is no central place to look for this answer, then please share how you find loaders that are needed to solve your webpack file loading problem.
It all depends on your workflow, how u want to load assets at run-time.
For eg, if u have lot of images, it might be a good idea to use a file-loader and place them directly inside the build directory.
The above approach will increase the GET calls and the bundled js file size will not be affeted
If u have less images/small size images then you can use url-loader which converts them into data-URL and put them inside your bundled js files.
The above approach will reduce the GET calls and will slightly increase the bundled js size.
If u want combination of both, then u can set a size limit and fallback loader(file-loader) on url-loader. What this will do is, the size of the dataURL will be calculated.If the size is grater than the limit, the file-loader will be used, which will place it in the build directory.
How I use them
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'images/',
name: '[name][hash].[ext]',
},
},
],
},
{
test: /\.(svg)$/,
exclude: /fonts/, /* dont want svg fonts from fonts folder to be included */
use: [
{
loader: 'svg-url-loader',
options: {
noquotes: true,
},
},
],
},
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
exclude: /images/, /* dont want svg images from image folder to be included */
use: [
{
loader: 'file-loader',
options: {
outputPath: 'fonts/',
name: '[name][hash].[ext]',
},
},
],
}
Why does webpack have separate loaders for loading css (css-loader) and injecting it to the website (style-loader), if first is useless without the second?
Could you point out a scenario in which I'd use css-loader without style-loader?
The style-loader loader is just one of many different ways to ultimately have your styles included on your page. For example, you could use the ExtractTextPlugin to generate a .css file separate from your bundle file:
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: ['css-loader']
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: 'app.css'
})
]
This gives you the flexibility to load your css separately from the rest of your bundle, so you can prevent FOUC.
I am building something like a static website generator that uses webpack to build the project and create a bundle with it.
In this project, a user is able to specify custom css files. I want those css files to be bundled with the final result. The issue is, that I do not have the paths to those css files available during development, so I can't do import 'some-asset-file-provided-by-the-user.css' in the javascript code that is going to be bundled. But I have them available when calling webpack.compile(config).
I am looking for a way to inject those css files into the bundle. So far I tried various ways, such as:
const stylesheet = 'some-asset-file-provided-by-the-user.css'
require(stylesheet)
Which did not work, probably because webpack is not able to deal with this "dynamic" require. Then I used the webpack define plugin for this
/* webpack.config.js */
new webpack.DefinePlugin({
stylesheet: 'some-asset-file-provided-by-the-user.css'
}),
/* app.js */
require(stylesheet) // should be replaced by the webpack define plugin with 'some-asset-file-provided-by-the-user.css'
which also did not work. I also tried to find a way to do something like this:
{
test: /\.css$/,
loader: ExtractTextPlugin.extract(Object.assign({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
useFiles: ['file-a.css', 'file-b.css']
}
}
]
}, extractTextPluginOptions))
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
which also failed because apparently neither style-loader nor css-loader support this type of interaction.
How can I solve this? I am open to writing a plugin for this, but I'd rather use something existing.
The simplest way to include the CSS is by adding it to your entry point. To make this easier, you should use an array as entry point even if it's just a single file, so you can simply push the CSS.
For example:
entry: {
app: ['./src/index.js'],
// Other entries
},
In your compile script you add it to entry.app before passing it to webpack.
config.entry.app.push('./user.css');
const compiler = webpack(config);
In the following example (found here), style-loader is being used as a fallback in development mode. Why?
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractSass = new ExtractTextPlugin({
filename: "[name].[contenthash].css",
disable: process.env.NODE_ENV === "development"
});
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: extractSass.extract({
use: [{
loader: "css-loader"
}, {
loader: "sass-loader"
}],
// use style-loader in development
fallback: "style-loader"
})
}]
},
plugins: [
extractSass
]
};
Extracting CSS from JavaScript is primarily used to not having to rely on your JavaScript (the bundle) being fully loaded until it injects the CSS into the head as a <style> tag, which can cause Flash of unstyled content (FOUC). And of course it's also used to simply separate CSS from JavaScript because that's generally preferred and allows being cached separately.
In development this doesn't really matter since the FOUC is basically a performance issue, just like the load time of your JavaScript, which hopefully you don't uglify in development either. This is neither your main concern nor representative in development mode. Besides being an additional compilation step, extracting CSS also imposes some drawbacks. For instance you lose hot reloading, because the newly compiled bundle didn't change as the content of the CSS has been extracted. The advantages are mostly aspects you care about for production and the drawbacks negatively affect development. See also Usage - Advantages and Caveats.
To be clear, the fallback is used after the configured loaders have been applied, it's just an extra step to be able to inject the CSS into a <style> tag from your JavaScript, which is the only thing that style-loader does. The fallback is used instead of extracting it to a file.