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]'
}
}
...
]
}
Related
In my public folder I have index.html, the css file and the fonts.
In my source folder I have the index.js file.
This is how the folder structure looks
I have setup the webpack.config.js file like this
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.join(__dirname, 'src', 'index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '',
filename: 'bundle.js',
},
mode: 'development',
module: {
rules: [
{
test: /\.?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/transform-runtime'],
},
},
},
{
test: /\.css$/i,
exclude: /node_modules/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
exclude: /node_modules/,
use: 'file-loader',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
exclude: /node_modules/,
use: 'url-loader',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'public', 'index.html'),
publicPath: './',
}),
],
};
Everything is working fine in dev, but when I create the build the files inside the public folder except the index.html are not included.
The dist folder after the build
You can use the copyWebpackPlugin to move the files from /public to the new build destination (/dist).
Example:
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "./public/*", to: "./" },
],
}),
],
};
However, how are you using this CSS and Font files? Webpack should also help to pack your CSS correctly along with the rest of your code. I recommend you to follow the oficial documentation: Webpack.
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";
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.
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.
I am using webpack (NOT the dev-server, I know that doesn't output a file), and it is not creating a dist folder or output file.
I've tried running it directly through webpack (installed globally) and npm run build which uses a locally installed webpack. Neither work.
Here's my config:
const path = require('path');
module.exports = {
entry: {
app: './src/entry.js',
},
output: {
path: path.join('/dist'),
filename: '[name].bundle.js',
},
module: {
loaders: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
},
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['ng-annotate'],
},
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel', // 'babel-loader' is also a legal name to reference
query: {
presets: ['es2015', 'latest'],
},
},
{
test: /\.css$/,
loader: 'style-loader!css-loader',
},
{
test: /\.html$/,
loader: 'html',
},
{
test: /\.less$/,
loader: 'style!css!less',
},
],
},
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js'],
root: [
path.resolve('./src'),
path.resolve('./node_modules'),
],
alias: {
vendor: path.join('/node_modules'),
},
fallback: ['node_modules'],
},
};
I've attempted to fix the problem by creating the dist folder manually, but that doesn't work either, the file still is not created.
The weird thing is that it DID build the file before, but now it's stopped. I've not changed the output location or the entry file at any point.
Any suggestions?
Your webpack output path is absolute:
output: {
path: path.join('/dist'), <----
filename: '[name].bundle.js',
},
My guess is it's being generated in your root directory. /dist would mean from the root of your file system, not relative to your project directory.
It should be:
output: {
path: path.join('./dist'),
filename: '[name].bundle.js',
},