write concatenated scss and compiled css to distribution folder with webpack - reactjs

We package React components as Node modules with Webpack (https://github.com/tocco/tocco-client). These modules shall self-contain all individual styles as a css-file for instant usage and as a scss-file for theming.
file structure before Webpack compilation
package-1/
dist/
src/
component-a/
component-a.js
component-a.scss
component-b/
component-b.js
component-b.scss
desired file structure after Webpack compilation
package-1/
dist/
package-1.js /* contains component-a.js and component-b.js */
package-1.css /* contains component-a.scss and component-b.scss */
package-1.scss /* contains component-a.scss and component-b.scss */
src/
component-a/
component-a.js
component-a.scss
component-b/
component-b.js
component-b.scss
With Webpack loaders it is possible to write package-1.css or package-1.scss, but not both files in a single run. It seems that all loaders with the same "test-pattern" are combined in a single task pipe.
Following implementations are based on https://github.com/webpack/extract-text-webpack-plugin
instaces of plugin
let extractSASS = new ExtractTextPlugin('index.scss')
let extractCSS = new ExtractTextPlugin('index.css')
Example 1: causes an error, because css-loader is rendered twice
webpackConfig.module.loaders.push(
{
test: /\.scss$/,
loader: extractSASS.extract('css-loader')
},
{
test: /\.scss$/,
loader: extractCSS.extract('css-loader!sass-loader')
}
)
Example 2: causes no error but only writes a css file
webpackConfig.module.loaders.push(
{
test: /\.scss$/,
loader: extractSASS.extract('css-loader')
},
{
test: /\.scss$/,
loader: extractCSS.extract('sass-loader')
}
)
Example 3: causes no error but only writes a scss file
webpackConfig.module.loaders.push(
{
test: /\.scss$/,
loader: extractSASS.extract('css-loader')
}
)
Example 4: causes no error but only writes a scss file
webpackConfig.module.loaders.push(
{
test: /\.scss$/,
loader: extractCSS.extract('css-loader!sass-loader')
}
)
Questions:
Is it possible to generate an output in the middle of a loader pipe?
Is it possible to generate an ouput per separateley defined loader, like it is intended with configuration "Example 1"?
Does Webpack demand a certain implementation for generating several outputs of one filetype (having several scss files and wanting one scss file and one css file)?

Related

React - Creating a reusable Components library (You may need an appropriate loader to handle this file type.)

when creating a package which will serve as a library of reusable components(A), I'm getting the error below[1] when trying to use any of its components in another project(B).
When developing in the package itself (A), I get no such errors and all works. The issue only occurs when trying to e.g.:
import Home from 'ReusableComps';
...
return (
<Home /> // <- Error here
...
I can get by this error by adding something like the below to my (B) webpack[2], but I reckon that this is not a good solution. Am I missing something in the webpack, babelrc etc. in project (A) perhaps?
Thanks
[1]
Module parse failed: Unexpected token (11:6)
You may need an appropriate loader to handle this file type.
[2]
module: {
rules: [
{
test: /\.js?$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env", "#babel/preset-react"]
}
}
}
],
}

How to override a webpack loader based on specific require needs?

I'm building a documentation site in which I want to display demo code snippets.
With the styles, it was really straight forward, as my app is only including the main.scss, so I'm processing that file with all the necessary loaders to compile it, and any other scss file is loaded using the raw-loader to get the file as plain text.
The problem I'm having is at the moment of doing the same with my components. Unlike my styles, I need to include my components both when I want to render them using babel-loader, but I also want to import them as plain text for the demo showcase.
At first I thought of compromising using an inline loader at the require level
const componentCode = require('raw-loader!./path/to/component');
The problem with this approach is that by the time I try to do this import, the file has already been ran through babel-loader so I get the compiled version of the file instead of the original. I tried passing ?enforce=pre as a query parameter to the raw-loader inline, but this had no effect.
I was wondering if there is a way of defining a rule to override an import/require statement.
According to the webpack documentation
It's possible to overwrite any loaders in the configuration by prefixing the entire rule with !.
However, I can not find any examples of this. I tried the following, which compiled but crashed right after the first ! prefixed require without any errors
webpack.coonfig.js
{
test: /\.(js|jsx)$/,
exclude: [/node_modules/],
use: [
{
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
},
},
],
},
{
test: /!*\.(js|jsx)$/,
enforce: "pre",
use: [
{
loader: 'raw-loader',
},
],
},
file.jsx
const componentCode = require('raw-loader!./path/to/component');
I also thought about reading the file using the fs but not sure if this will work. In the end the code will be compiled in its entirety by webpack and only the bundle will be published. Would this be the right approach?
Found my answer at Webpack - ignore loaders in require()?, Basically I need !! before the require to ignore the pre loaders and apply mine

sass-loader fails to work (You may need an appropriate loader to handle this file type.)

Hi all I am following the instructions as posted on https://github.com/yibn2008/fast-sass-loader for this sass loaders. The reason I choose it is because I am using webpack 1. Currently my module looks like
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: ['react-hot', 'babel'],
include: SRC_DIR
},
{
test: /\.(scss|sass)$/i,
loaders: ["style-loader", "css-loader", "fast-sass-loader"]
}
]
}
when I go to look at my localhost I get this errror
ERROR in ./src/common/css/common.sass
Module parse failed: C:\Users\Administrator\Documents\backup\src\common\css\comm
on.sass Invalid number (1:7)
You may need an appropriate loader to handle this file type.
SyntaxError: Invalid number (1:7)
Not sure what the problem is, can any point me in the right direction or tell me of another sass loader that works with webpack 1?
Update 1
I realized that in my import statement when I do '!style!css-loader!fast-sass!' it works but I do not want to do that every time. Why will the loader in webpack not work?

Webpack 1 + sass (in react) - leave my images alone

I have a project in React.js with SASS and using Webpack 1.
I have images folders with all the images and other assets' folders.
I do not want webpack to do anything with images, I want them to be loaded at the runtime by url.
I solved it in JSX by using image urls inline in the jsx code (rather then importing them) and it's working great.
But when I'm trying to do the same in SASS, it's different:
I used to refer to them in absolute pass /images/abc.png and it worked.
I didn't even had a webpack loader for them, it just worked.
But I had to change it to the relative path ../../www/images/abc.png and it's all broke down:
It refuses to work without webpack loader - just gives errors for each image.
I've tried using file-loader, but it copies all sass's used images into build folder.
I've tried using url-loader, but it just included the images into resulting css file making it enormously bloated.
So, what could I use to ignore the images from sass and just address them by url in the runtime?
Thanks
One possibility is to set the url option of the css-loader to false, so webpack won't touch the urls. Your rule for .scss could look something likes this (assuming you use extract-text-webpack-plugin):
Webpack 1:
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?url=false!sass-loader')
},
Webpack 2:
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader', options: { url: false } },
{ loader: 'sass-loader' }
]
})
}
But that ignores all urls not just your images. If that is a problem you could use file-loader with the option emitFile: false so it won't copy your files. But you'll need some workaround to get the correct path. When using [path] in the name it will use the relative path from the context. Because you're building it to a directory (e.g. build/) you'll need to go up one directory (../) by setting the publicPath option. Which would give you the following rule:
Webpack 1:
{
test: /\.png/,
loader: 'file-loader?emitFile=false&name=[path][name].[ext]&publicPath=../'
},
Webpack 2:
{
test: /\.png/,
loader: 'file-loader',
options: {
emitFile: false,
name: '[path][name].[ext]',
publicPath: '../'
}
}
If you've set context in your webpack config or your output CSS file is more than one level deep in the build directory, you'll need to tweak the publicPath option.

Webpack with babel-loader does not recognize JSX code

I'm having trouble getting a quite basic setup with webpack and babel working. I need babel to compile JSX, i don't use ES2015 features.
There are quite a few questions here on SO about this exact problem, but they all seem to be resolved by installing babel-preset-react or adding the preset option to babel in webpack.config.js all of which i have done already (I think).
I'm sure it's a simple thing I'm missing, but I just can't see it.
I extracted just the files needed to demonstrate my problem into this gist (i used dashes in the filenames to indicate subfolders since you can't have folders in gists). My webpack.config.js looks like this:
module.exports = {
entry: [
'./app/js/app.js'
],
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
include: __dirname + '/app/js/',
loader: 'babel-loader?presets[]=react',
}
]
},
output: {
filename: "bundle.js",
path: __dirname + '/public'
},
};
Note: in package.json everything is listed under 'dependencies', since i'm hosting this on heroku which does not install devdependencies (at least not by default)
For what it is worth, I am currently using webpack with latest babel with the following config line
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
}
Since you don't use es2015, you should be able to just leave the react preset in the list. Maybe babel-loader?presets[]=react is not working the way you expect it to.
I banged my head against this for a long time as well. It turned out that the include wasn't finding my directories. The easiest way to fix, as pointed out in the comment to the marked answer above, is to use an exclude, e.g. exclude: /node_modules/, or whatever you need to exclude, and it'll start working.
If you're new to webpack, you'll find the error you get from the above kind of cryptic (will look like a parse error on your js, even though you thought babel should have transformed the JSX; the deal is that it didn't).

Resources