Webpack removes css from .jsx files? - javascript

I have webpack file that looks like this (note - for now - I need to create both minified and not minified versions of assets - so this is not a mistake):
const path = require('path');
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const readSass = new ExtractTextPlugin({
filename: "foo/bar/style.min.css"
});
config = {
entry: {
"main": './main.js',
"main.min": './main.js',
"style.min": './style.scss'
},
watch: true,
devtool: "source-map",
output: {
path: path.resolve(__dirname, '/dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.jsx?$/i,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['es2015', 'react'],
minified: true
}
},
{
test: /\.scss|css$/,
use: readSass.extract({
use: [{
loader: "css-loader", options: { minimize: true }
}, {
loader: "sass-loader"
}]
})
}
],
},
plugins: [
readSass,
new UglifyJsPlugin({
include: /\.min\.js$/
})
],
}
module.exports = config;
Everything works as expected, but there's one thing that bugs me.
In a few of my .jsx files I have CSS modules being loaded from different third-party components, stuff like:
import 'react-plugin/react-plugin.css';
Of course my compiled js and css files do not contain these styles. They're lost on the way. All the css from style.scss are there, all the js from main.js and jsx included within it are there, but theses styles are not.
What am I doing wrong?

that is simply because you are using extract-text-webpack-plugin module. if you want to keep your sass in your bundle then modify your webpack config into this:
const path = require('path');
const webpack = require("webpack");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
config = {
entry: {
"main": './main.js',
"main.min": './main.js'
},
watch: true,
devtool: "source-map",
output: {
path: path.resolve(__dirname, '/dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.jsx?$/i,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['es2015', 'react'],
minified: true
}
},
{
test: /\.scss|css$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
],
},
plugins: [
readSass,
new UglifyJsPlugin({
include: /\.min\.js$/
})
],
}
module.exports = config;
and instal sass-loader and style-loader by this command: npm install -D sass-loader style-loader
EDIT: I forgot to tell you, you have to include your css or sass before your js entry point like this
require('path/to/your/main.scss')
ReactDOM.render(<App />, document.getElementById('root'))
so that it is bundled together AND you don't have to include your css in the webpack config entry point anymore.

The sass required not declare yet?it's possible to use ./sass/**/*.css/\ on your test to call any css style translate from sass.

Can you see what happens when you include style-loader too, like so:
$ npm i -D style-loader
//... webpack.config.js
{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader"
}],
exclude: /node_modules/
},
Edit: remove the exclude: /node_modules/ if you need to load files from there.
Then ensure you are importing it in your js entrypoint: import "../css/main.scss";

Related

react production build, assets not loading

I am experiencing annoying problem, when i run my react app in development environment it all works ok, but when i try to build to production, all the links are wrong.
assume this tree:
main_directory
public/
svg/
some_img.svg
src/
components/
some_component.jsx
App.js
index.js
Now in some_component.jsx i am referencing svg file in this way:
src="/public/svg/some_img.svg"
however after building to production this path is untouched and therefore cannot access file anymore, as there i would need it to be changed to this:
src="svg/some_img.svg"
i was playing in the webpack config file, i thought that maybe by setting:
publicPath: "/"
to:
publicPath: "/public/"
would resolve the problem but the only thing it did was error during application start:
CANNOT GET/
my webpack config:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const htmlPlugin = new HtmlWebPackPlugin({
template: "./public/index.html",
filename: "./index.html"
});
module.exports = {
output: {
filename: "main.[hash:8].js",
publicPath: "/"
},
module: {
rules: [
{
test: /\.jsx$/,
exclude: /node_modules/,
loader: "babel-loader?presets[]=react"
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(sass|scss)$/,
use: ["style-loader", "css-loader", "sass-loader", "postcss-loader"]
},
{
test: /\.svg$/,
loader: "svg-sprite-loader"
}
]
},
plugins: [htmlPlugin],
devServer: {
historyApiFallback: {
rewrites: [{ from: /^\/$/, to: "/index.html" }]
}
},
resolve: {
extensions: [".js", ".jsx", ".json"]
}
};
How does one resolve this problem, so for both dev and production paths are unified?
How about importing the svg and then referencing the imported variable:
import someImg from "../../public/svg/some_img.svg"
src={someImg}
this is the solve for the question, config required for to specify path:
module: {
...
rules: [
{
test: /\.(png|jpg|gif|svg|ico)$/,
loader: 'file-loader',
query:{
outputPath: './img/',
name: '[name].[ext]?[hash]'
}
}
...
]
}

Mini-css-extract-plugin doesn't bundle my css into one single file with sass

When i try to add the sass-loader and run webpack there is multiple chunck .css files in the dist folder instead of just the bundled one named "style.css".
My dist output folder looks like:
0.e749007119be51de03e4.js 1.e749007119be51de03e4.js bundle.e749007119be51de03e4.js
0.style.css 1.style.css
I guess it's because of the Mini-css-extract-plugin but i can't figure out how to fix it.
Here is my webpack file:
const webpack = require('webpack');
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ROOT = resolve(__dirname);
const SRC = resolve(ROOT, 'src');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
entry: {
bundle: [
'react-hot-loader/patch',
'webpack-hot-middleware/client?reload=true',
resolve(SRC, 'client', 'index.js'),
]
},
output: {
path: resolve(ROOT, 'dist', 'client'),
filename: '[name].[hash].js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
include: resolve(__dirname, 'node_modules', 'react-toolbox'),
use: [
MiniCssExtractPlugin.loader,
// 'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
// 'postcss-loader'
]
},
{
test: /\.scss$/,
use: ['style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
},
{
test: /\.css$/,
exclude: resolve(__dirname, 'node_modules', 'react-toolbox'),
use: ['style-loader', 'css-loader']
},
{
test: /\.(jpe?g|svg|png|gif)$/,
use: ['file-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename: 'style.css',
}),
]
};
Any idea ?
There is two problems coming with this way. If i wanna use a plugin like html-webpack-plugin the index.html file is not filled with the anymore. Secondly the normal behavior of MiniCssExtractPlugin shouldn't be to create a file style.css like i precised in the constructor ?
No, since you have async chunks, it is going to create a style.css for each style that is removed from those async chunks.
I assure you that if you are using html-webpack-plugin it is going to work. It is just not added there because those css had not came from one of the entry points. THat is why it is not inserted directly into the html. I have a similar project and it works perfectly.
If those are not emmited from the entry point, there are going to be loaded dynamically by webpack once those chunks are requested.
Big files harms users. Code splitting is always the answer for everything!!
Check out this piece of code from the documentation
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
}
]
}
if you see carefully you'll see that it's using style-loader in dev mode and MiniCssExtractPlugin.loader for production. So in production it will generate another file for css.
What you need to do is this:
In your package.json file in the script section you need to pass a env variable devMode like this
"scripts": {
"webpack": "webpack",
"start": "npm run webpack -- --env.mode=development"
}
Then in your webpack.config.js file you need to do this
module.exports = (env) => {
const devMode = env.mode === 'development'
return {
mode: env.mode, // will be development
devtool: ...,
entry: { ... },
output: { ... },
module: {
rules: [
{
test: /\.scss$/,
use: [devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}
]
}
}
}
That should be ok, hope it helps.

Compile scss with webpack for an Angular App

I'm using webpack 3 for my angular app. I have some issues with compiling my scss files. Here is full webpack config file:
const path = require('path')
const autoprefixer = require('autoprefixer')
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const config = {
context: __dirname + '/src',
entry: {
app: './index.js',
vendor: [
'angular',
'angular-animate',
'angular-bootstrap',
'angular-route',
'animate',
'bootstrap',
'bootstrap-filestyle',
'jquery',
'ng-file-upload',
'ng-parallax'
]
},
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'app'),
publicPath: path.join(__dirname, 'app')
},
resolve: {
extensions: ['.js', '.jsx', '.scss']
},
module: {
loaders: [
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style-loader',
'css?minimize!postcss!sass')
},
{
test: /\.(eot|woff|woff2|ttf|svg)(\?\S*)?$/,
loader: 'file?name=fonts/[name].[ext]'
},
{
test: /\.(jpg|jpeg|gif|png|svg)$/,
loader: 'file?name=images/[name].[ext]'
}
],
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
},
{
test: /\.svg$/,
loader: 'url-loader'
},
{
test: /\.php$/,
loader: 'file-loader?name=[name].[ext]'
},
{
test: /\.zip$/,
loader: 'file-loader?name=[name].[ext]'
},
{
test: /(\.png|\.jpg|\.gif)$/,
loader: 'file-loader?name=[path][name].[ext]'
}
]
},
plugins: [
new ExtractTextPlugin('./bundle.css'),
new CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.bundle.js'
}),
new UglifyJSPlugin({})
// new ExtractTextPlugin({
// filename: '[name].min.css'
// })
]
}
module.exports = config
After running webpack i've got this error:
ERROR in ./assets/sass/main.scss
Module parse failed: /home/git/project/src/public/src/assets/sass/main.scss Unexpected token (1:13)
You may need an appropriate loader to handle this file type.
| $header-color: #ffffff;
| $admin-panel-height: 40px;
|
# ./index.js 3:0-34
Also i tried to use this loader: https://github.com/webpack-contrib/sass-loader
After webpack build there no errors appeared, but css file also was not created in /app folder.
file main.scss imports in index.js:
import './assets/sass/main.scss'
Can anyone give me an advice how can i build and watch scss files with webpack 3 ?
You have used some of the loader configs that suppose to be for webpack 1.
That section of the config:
loaders: [
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style-loader',
'css?minimize!postcss!sass')
},
{
test: /\.(eot|woff|woff2|ttf|svg)(\?\S*)?$/,
loader: 'file?name=fonts/[name].[ext]'
},
{
test: /\.(jpg|jpeg|gif|png|svg)$/,
loader: 'file?name=images/[name].[ext]'
}
],
There are breaking changes when you move to Webpack 2 (or 3).
One of them was module.loaders => module.rules.
You will need to convert that section to the new structure.
In addition, ExtractTextPlugin changes it config style as well, please read it README.

Why webpack gives back the mistake ReferenceError: document is not defined?

The text of the mistake
ERROR in ./static/main.sass
Module build failed: ModuleBuildError: Module build failed:ReferenceError: document is not defined
ERROR in ./~/css-loader!./~/resolve-url/resolve-url.js!./~/sass-loader?sourceMap!./static/main.sass
Module build failed: ReferenceError: document is not defined
at Object.resolveUrl (/home/andrew/Test/node_modules/resolve-url/resolve-url.js:21:25)
The webpack.config.js
webpack = require('webpack');
path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
webpackConfig = {
context: __dirname,
entry: {
bundle: './static/app.js',
styles: './static/main.sass'
},
output: {
filename: '[name].js',
path: './static/build'
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devtool: '#cheap-module-source-map',
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: [/node_modules/],
loader: "babel-loader",
query: {
presets: ['es2015', 'react', 'stage-0', 'stage-1']
}
},
{
test: /\.sass$/,
loader: ExtractTextPlugin.extract( 'css-loader!resolve-url!sass-loader?sourceMap')
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
},
{
test: /\.woff2?$|\.ttf$|\.eot$|\.svg$|\.png|\.jpe?g|\.gif$/,
loader: 'file-loader'
}
]
},
plugins: [
new ExtractTextPlugin('styles.css', {
allChunks: true
})
]};
module.exports = webpackConfig;
I thought it may be not having some of the loaders but that's not it.
Besides app.js does not compile in bundle.js too but it doesn't give a mistake. Maybe there is some mistake in entry but I don't know.
You need to include the SCSS file in your app.js (either require or import) and only pass your app.js file as entry for Webpack instead of passing the 2 files as entry.

Webpack force re-render (re-build, re-compile) via CLI webpack tool

Somethimes webpack doesn't pick up my changes to jsx and scss files, and hence it doesn't compile updated main.scss and main.js (sometimes).
The webpack runs inside docker container installed in alpine linux light-weight environment.
I want to ssh into docker container and forcefully recompile the changes via webpack command line tool directly.
There might be some manual way like
$ webpack --force-complie or --force-watch or something like that to manualy run the rebuild process of main.scss and main.js
is there any way to do so?
here is my webpack.config.js file:
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const webpack = require("webpack");
const autoprefixer = require("autoprefixer");
if (process.env.NODE_ENV === "development") {
require("dotenv").config();
}
module.exports = {
entry: "./assets/shared/main.jsx",
output: {
path: "public",
publicPath: "/",
filename: "main.js"
},
module: {
preLoaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
loader: "eslint-loader"
}
],
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
loader: "babel-loader",
query: {
presets: ["react", "es2015", "stage-0"]
}
},
{
test: /\.scss$/,
exclude: /(node_modules)/,
loader: ExtractTextPlugin.extract(
"style-loader",
"css-loader?sourceMap!postcss-loader!sass-loader"
)
},
{
test: /\.(png|jpg)$/,
// inline base64 URLs for <=4k images, direct URLs for the rest
loader: "url-loader?limit=4096"
}
]
},
devtool: "source-map",
stats: { children: false },
postcss: function () {
return [autoprefixer];
},
eslint: {
quiet: true
},
plugins: [
new ExtractTextPlugin("styles.css"),
new webpack.EnvironmentPlugin([
"NODE_ENV", // This is used to run React in "production" mode
"API_URL"
])
]
};

Categories