In my project I use Webpack with React and NodeJS. I want to generate a bundle.js and style.css file. Currently I've got the following code:
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
entry: './index.js',
output: {
path: 'public',
filename: 'bundle.js',
publicPath: ''
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
},
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('css!sass') }
]
},
plugins: [
new ExtractTextPlugin('public/style.css')
]
}
But when I run webpack only the JS file is created in the ./public map:
Asset Size Chunks Chunk Names
bundle.js 844 kB 0 [emitted] main
+ 222 hidden modules
Following examples/tutorials it's only oriented on CSS files, or obvious mistakes where made like not implementing ExtractText.
I've also downloaded the packages sass-loader node-sass. In some examples I did found those packages where included, in some they weren't.
EDIT (require style in index.js):
import React from 'react'
import { render } from 'react-dom'
import { Router, browserHistory } from 'react-router'
import routes from './modules/routes'
require('./public/style.css')
render(
<Router routes={routes} history={browserHistory} />,
document.getElementById('app')
)
EDIT (webpack.config.js):
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
},
{
test : /\.scss$/,
include : path.join(__dirname, './public/sass'),
loaders : ["style", "css", "sass"]
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass')
}
]
},
sassLoader: {
includePaths: [path.join(__dirname, './public/sass')]
},
plugins: [
new ExtractTextPlugin(path.join(__dirname, './public/style.css'))
]
My folder structure looks like this:
webpack.config.js
index.js
/public
index.html
bundle.js (generated)
/sass
style.scss
basics.scss (imported in style.scss)
Make sure that you require your style file.
e.g.
require('../sass/app.scss');
and I think you need style loader as well
e.g.
{
test : /\.scss$/,
include : path.join(__dirname, 'sass'),
loaders : ["style", "css", "sass"]
}
These three loaders perform following operations
Turn your scss files into plain CSS with the sass loader
Resolve all the imports and url(...)s in the CSS with the help of CSS loader
Insert those styles into the page with the style loader
You need a combination of the ExtractTextPlugin and the style loader.
module: {
loaders: [
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!sass-loader'),
},
],
}
...
plugins: [
new ExtractTextPlugin(path.join(__dirname, 'public', 'style.css')),
],
In my working configs, I also have a possibly extraneous entry in resolve:
resolve: {
loaders: [
{
test: /\.(css|scss)$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader'),
},
],
},
The other error might be how you're including it in index.js. You're using require('./public/style.css') rather than require('./public/style.scss').
Related
I have gone through a lot of questions on stackoverflow and article before writing this question here.
I am successfully able to create the CSS file sass using webpack4.
I have file as below client.js, it import the scss
import React , { Component } from 'react'
import { connect } from 'react-redux';
import './jobcard.scss';
here is my webpack config.
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
client: './src/client.js',
},
output: {
path: path.resolve(__dirname, 'asset'),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'main.css',
})
]
}
It successfully creating the main.css and store in the '/asset' folder.
but the problem is when I complied client.js using babel. it has below the line.
require("./jobcard.scss");
its breaks due to the above line because in dist folder there is no such scss file as it's extract and placed in 'asset' folder. I want my css/image in 'asset' folder.
my expectation is my final css moved to '/asset' folder which is happening right now and the above line should get removed from complied client.js file.
So I can refer the main.css on my index.html from asset location.
Try with this config to see if it work for you
module: {
rules: [{
test: /\.scss$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
minimize: true,
sourceMap: true
}
},
{
loader: "sass-loader"
}
]
}
]
}
ERROR in ./client/index.js
Module build failed: SyntaxError: Unexpected token (31:4)
const Root = () => {
return (
<ApolloProvider client={client}>
^
<Router history={hashHistory}>
My Webpack config file below:
const path = require('path'),
webpack = require("webpack"),
clientPath = path.join(__dirname, 'client'),
HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.join(clientPath, 'index.js'),
output: {
path: __dirname,
filename: 'bundle.js'
},
module: {
rules: [
{
use: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
},
{
use: ['style-loader', 'css-loader'],
test: /\.css$/
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: [
'file-loader?hash=sha512&digest=hex&name=[hash].[ext]',
'image-webpack-loader?bypassOnDebug&optimizationLevel=7&interlaced=false'
]
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file-loader'
}
],
loaders: [
{ test: /\.jsx$/, exclude: /node_modules/, loader: "babel-loader" }
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'client/index.html'
})
]
};
I am not able to build , it throws Unexpected token error while I have no syntactical mistake in code, Its just not able to recognise react code style
I have tried changing js to jsx inside webpack config at this place
{
use: 'babel-loader',
test: /\.jsx$/,
exclude: /node_modules/
}
Then it throws different error like
Module parse failed: /client/index.js Unexpected token (31:4)
You may need an appropriate loader to handle this file type.
It was my mistake only, ".babelrc" file was missing in my directory so I have created a file inside my app directory at root level and put this content into that file
.babelrc
{
"presets": ["env", "react"]
}
And tried with npm run-script build....succeeded!!!!
I see two possible causes:
1) loaders: [
{ test: /\.jsx$/, exclude: /node_modules/, loader: "babel-loader" }
] will do nothing as loaders should be specified in module.rules so nothing is handling jsx files. This can be done to handle both js and jsx files using regex /\.jsx?/
2) The babel loader has no presets so unless they are specified in a .babelrc ypou arent showing, then you need to add the necessary presets to the loader
These should both be remedied by...
npm install babel-preset-react babel-preset-es2015
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
//...
}
hey people I need help with the following:
am creating React UI component library
I am using webpack and dev build works great, scss files are loaded and components are displayed correctly
on production build, JS bundle is created as well as CSS (I use SCSS) bundle
BUT when I install the library in another React project and import the component, CSS is not loaded (cmp is not styled), JS works fine and the component is rendered yet styles are not loaded...
EDIT
Apparently this approach requires manual loading of CSS in parent app project. Which I want to avoid. Is there alternative way which can provide scenario in which styles will be resolved on the level on component without need for manual loading?
Here is my production webpack config:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, '../lib'),
libraryTarget: 'commonjs',
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader']
})
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader']
})
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
options: {}
}
}
]
},
externals: {
'react': 'commonjs react',
'react-dom': 'commonjs react-dom',
},
resolve: {
modules: [
path.resolve('./src'),
path.resolve('./node_modules')
]
},
plugins: [
new ExtractTextPlugin({
filename: 'ui-library.css'
})
]
};
You could simply not use ExtractTextPlugin.
The whole purpose of Webpack is to group assets not based on file type but by a component perspective.
So, if you remove ExtractTextPlugin, your CSS will be included in your .js bundle.
I have an app that is in a different folder structure than the modules installed from the package.json and I cannot find a way to make it work:
Structure:
includes
build
build stuff
src
shared assets
js
...APP (the app is a few folders down still)
How can I specify that the modules are somewhere and the app is in another place? Is this even possible? as If I set up the src of my app in the place where the build setup is, everything work as expected.
Where is my very simple webpack config.
var getters = require('./../gulpfile.js/config/getters');
var path = require('path');
var appRoot = path.resolve(__dirname, '../src');
var appRoot2 = path.resolve(__dirname, '../../main/jcr_root/etc/designs/fit/includes/shared_assets/js/vueapps/chat_app/src');
module.exports = {
context: appRoot2,
entry: './main.js',
output: {
filename: 'app.js',
path: getters.js.vue.apps.chatapp.dist
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
exclude: /node_modules/
},
{
test: /\.js$/,
loaders: 'babel-loader',
exclude: /node_modules/
}
]
},
resolve: {
modules: [
'node_modules'
]
}
};
I this you can see I have appRoot and appRoot2, appRoot works as expected, appRoot2 fails giving me this error.
ERROR in Entry module not found: Error: Can't resolve 'babel-loader' in ...
EDIT: Forgot to mention I'm using :
"vue-loader": "^9.4.0".
"webpack": "^2.2.0".
"babel-loader": "^6.3.2".
EDIT2: Got it working, had to specify with another option:
resolveLoader: {
modules: [
nodeRoot
],
}
Also in the loader had to add this option:
{
test: /\.js$/,
loaders: 'babel',
exclude: /node_modules/,
query: {
presets: [nodeRoot + '/babel-preset-es2015'],
}
}
With the path to the preset.
I am using the package electron-notifications and it relies on a .html and .css file in its assets folder. This assets folder is not included in webpack (1.14.0) though.
I know I should not add a module as an entry point. I have come across a concept called code splitting, but I'm not clear on how that works and if that is what I need to be looking into further. Any advice you can give would be greatly appreciated.
webpack.config.production.js
import path from 'path';
import webpack from 'webpack';
import validate from 'webpack-validator';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import merge from 'webpack-merge';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import BabiliPlugin from 'babili-webpack-plugin';
import baseConfig from './webpack.config.base';
export default validate(merge(baseConfig, {
devtool: 'inline-source-map',
entry: [
'babel-polyfill',
'./app/index'
],
output: {
path: path.join(__dirname, 'app/dist'),
publicPath: '../dist/'
},
module: {
loaders: [
// Extract all .global.css to style.css as is
{
test: /\.global\.css$/,
// loaders: [
loader: ExtractTextPlugin.extract(
'style-loader',
'css-loader?sourceMap'
)
// ]
},
// Pipe other styles through css modules and append to style.css
{
test: /^((?!\.global).)*\.css$/,
// loaders: [
loader: ExtractTextPlugin.extract(
'style-loader',
'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
)
},
// Fonts
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream' },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file' },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml' },
// Images
{
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
loader: 'url-loader'
}
]
},
plugins: [
// https://webpack.github.io/docs/list-of-plugins.html#occurrenceorderplugin
// https://github.com/webpack/webpack/issues/864
new webpack.optimize.OccurrenceOrderPlugin(),
// NODE_ENV should be production so that modules do not perform certain development checks
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new BabiliPlugin(),
new ExtractTextPlugin('style.css', { allChunks: true }),
new HtmlWebpackPlugin({
filename: '../app.html',
template: 'app/app.html',
inject: false
})
],
// https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
target: 'electron-renderer'
}));
If you want that packages' CSS to be recognised by the webpack, you just add it to the style's(CSS's) loader block, as an include attribute along with "test" and "loader". In the include attribute point it to the node_modules/electron_notification path.
HTML of that package need not be included, since your Single Page Application, has it's own HTML, if needed try to replicate the class names there. But I doubt if you need to do that.