Resolving relative paths in React with Webpack not working - reactjs

I have a react project and I am using webpack. I have a component in frontend/app/components/editor/index.js that I want to include in another component. Currently in order to reference this component I am having to use a relative path (../../../../app/components/editor). However, this is very not easy to use and would like to simply use 'components/editor' for example. My Webpack config file in in fronted/webpack.config.js.
I have added a resolve setting as in this post (Resolving require paths with webpack) but it's still not working.
const {resolve} = require('path');
const path = require('path');
const webpack = require('webpack');
const validate = require('webpack-validator');
const {getIfUtils, removeEmpty} = require('webpack-config-utils');
module.exports = env => {
const {ifProd, ifNotProd} = getIfUtils(env)
return validate({
entry: './index.js',
context: __dirname,
output: {
path: resolve(__dirname, './build'),
filename: 'bundle.js',
publicPath: '/build/',
pathinfo: ifNotProd(),
},
devtool: ifProd('source-map', 'eval'),
devServer: {
port: 8080,
historyApiFallback: true
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{test: /(\.eot|\.woff2|\.woff|\.ttf|\.svg)/, loader: 'file-loader'},
],
},
resolve: {
root: path.resolve('./app'),
},
plugins: removeEmpty([
ifProd(new webpack.optimize.DedupePlugin()),
ifProd(new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false,
quiet: true,
})),
ifProd(new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"',
},
})),
ifProd(new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
screw_ie8: true, // eslint-disable-line
warnings: false,
},
})),
])
});
};
These are all the settings I have tried in the resolve block but nothing works.
resolve: {
alias: {
shared: path.resolve(__dirname, 'app')
},
resolve: {
root: path.resolve('./app')
},
resolve: {
modules: ['app']
},
resolve: {
modulesDirectories: ['app']
},

Actually, it has to be
model.exports = env => {
...,
resolve: {
modules: ['app', 'node_modules']
},
...
}
So modules is a property of resolve object which itself is a property of the global configuration object. Also, I have included node_modules, because it's likely you want to refer to those as well after you overwrite the default, which is just [ 'node_modules' ]. See docs for more information.
Update based on comment
You are getting an error from webpack-validator, which is not gonna be maintained because of the inbuilt webpack validator. See more in this SO answer and webpack-validator npm. So the error [1] "modules" is not allowed is incorrect. To fix it you need to remove/uninstall webpack-validator.

Related

Build bundle.js in create-react-app application

Made a project. Now we need to collect everything in one bundle.js, and not in the way create-react-app does.
Executed the eject command, configs appeared. But how do i get bundle.js?
It is important that everything that is in the project (styles, pictures, etc.) be gathered into one file.
## My Solution
webpack.config.js:
const path = require("path");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
context: __dirname,
entry: "./src/index.js",
output: {
path: path.join(__dirname, "/dist"),
publicPath: '',
filename: "widget.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(gif|png|jpe?g|svg|woff(2)?|ttf|eot)$/i,
use: [
{
loader: 'file-loader',
options: {
publicPath: 'img',
outputPath: 'img',
name: '[name].[ext]',
},
},
],
}
]
},
optimization: {
minimizer: [new UglifyJsPlugin({
uglifyOptions: {
warnings: false,
parse: {},
compress: {},
mangle: true,
output: {
comments: false,
},
toplevel: false,
nameCache: null,
ie8: true,
keep_fnames: false,
},
})],
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html"
})
]
};
Ejecting is a real bad solution, instead use rewire npm install react-app-rewired and add a customized build script.
please checkout my answer here
How to build a production version of React without minification?

Webpack 2/React: cannot get style to work

I've been stuck here for hours now - can't include my style in development mode with webpack.config.js, and can't bundle my styles when I build my project with webpack.config.prod.js - or inject the style link into the generated index-template.html. Instead, no css file is generated - and the generated html file does not include style tag:
I've done this in other React/Webpack projects with no problems, where identical configuration results in both style tag and bundled css file:
I don't understand where I am going wrong .. this is my folder structure:
This is my webpack.config.js file:
const webpack = require('webpack');
const path = require('path');
const entry = [
'babel-polyfill',
'webpack-dev-server/client?http://127.0.0.1:8080', // Specify the local server port
'webpack/hot/only-dev-server', // Enable hot reloading
'./scripts/index.js' // Where webpack will be looking for entry index.js file
];
const output = {
path: path.join(__dirname, 'dist'), // This is used to specify folder for producion bundle
publicPath: '/dist',
filename: 'bundle.min.js' // Filename for production bundle
}
const plugins = [
new webpack.HotModuleReplacementPlugin(), // Hot reloading
new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
// Declare global variables
new webpack.ProvidePlugin({
React: 'react',
ReactDOM: 'react-dom',
_: 'lodash'
})
]
const config = {
context: path.join(__dirname, 'src'),
entry: entry,
devtool: 'inline-source-map',
devServer: {
historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
},
output: output,
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
use: {
loader: "babel-loader"
}
},
{
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
},
plugins: plugins
}
module.exports = config;
and this is my webpack.config.prod.js file:
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const entry = [
'./scripts' // Where webpack will be looking for entry index.js file
];
const output = {
path: path.join(__dirname, 'dist'), // This is used to specify folder for producion bundle
publicPath: '/dist',
filename: 'bundle.min.js' // Filename for production bundle
}
const plugins = [
new webpack.HotModuleReplacementPlugin(), // Hot reloading
new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
// Declare global variables
new webpack.ProvidePlugin({
React: 'react',
ReactDOM: 'react-dom',
_: 'lodash'
}),
new ExtractTextPlugin({
disable: false,
filename: 'bundle.css',
allChunks: true
}), // extract you css into seperate file files to serve your webpack bundles
new HtmlWebpackPlugin({
filename: 'index.html',
template: './index.html',
hash: false,
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'bundle',
filename: 'bundle.common.js'
})
]
const config = {
context: path.join(__dirname, 'src'),
entry: entry,
devtool: 'source-map',
devServer: {
historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
},
output: output,
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
use: {
loader: "babel-loader"
}
},
{
test: /\.(sass|scss)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: (loader) => [ require('autoprefixer')() ]
}
},
'sass-loader',
]
})
}
]
},
plugins: plugins
}
module.exports = config;
I am so effing thankful for any input <3
As #margaretkru said, I had forgotten to import my app.scss in my index.js file!

material-ui.dropzone: You may need an appropriate loader to handle this file type

Integrating material-ui-dropzone in my React app, I got this error:
./~/material-ui-dropzone/src/index.jsx Module parse failed:
...\client\node_modules\material-ui-dropzone\src\index.jsx Unexpected
token (123:26) You may need an appropriate loader to handle this file
type. SyntaxError: Unexpected token (123:26)
Here is my webpack configuration:
const Path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const Webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = (options) => { const ExtractSASS = new ExtractTextPlugin(`/styles/${options.cssFileName}`);
const webpackConfig = {
devtool: options.devtool,
entry: [
`webpack-dev-server/client?http://localhost:${+ options.port}`,
'webpack/hot/dev-server',
Path.join(__dirname, '../src/app/index'),
],
output: {
path: Path.join(__dirname, '../dist'),
filename: `/scripts/${options.jsFileName}`,
},
resolve: {
extensions: ['', '.js', '.jsx'],
},
module: {
loaders: [{
test: /.jsx?$/,
include: Path.join(__dirname, '../src/app'),
loader: 'babel',
}],
},
plugins: [
new Webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(options.isProduction ? 'production' : 'development'),
},
"global.GENTLY": false
}),
new HtmlWebpackPlugin({
template: Path.join(__dirname, '../src/index.html'),
}),
],
node: {
__dirname: true,
},
};
if (options.isProduction) {
webpackConfig.entry = [Path.join(__dirname, '../src/app/index')];
webpackConfig.plugins.push(
new Webpack.optimize.OccurenceOrderPlugin(),
new Webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
},
}),
ExtractSASS
);
webpackConfig.module.loaders.push({
test: /\.scss$/,
loader: ExtractSASS.extract(['css', 'sass']),
}); } else {
webpackConfig.plugins.push(
new Webpack.HotModuleReplacementPlugin()
);
webpackConfig.module.loaders.push({
test: /\.scss$/,
loaders: ['style', 'css', 'sass'],
});
webpackConfig.devServer = {
contentBase: Path.join(__dirname, '../'),
hot: true,
port: options.port,
inline: true,
progress: true,
historyApiFallback: true,
stats: 'errors-only',
}; }
return webpackConfig;
};
Babel config file is:
{
"presets": ["react", "es2015", "stage-1"]
}
It is the only library I had problems with. Any idea where might be the problem?
if you are using webapck#3.x
Try to modify your babel loader to
module: {
rules: [
{
test: /\.jsx?$/,
include: Path.join(__dirname, '../src/app'),
use: {
loader: 'babel-loader',
options: {
presets: ["react", "es2015", "stage-1"],
}
}
}
]
}
You can reference here https://webpack.js.org/loaders/babel-loader/
Noted that in your loader config, write babel-loader instead of just babel. Also make sure if you have npm install the right babel npm packages to the devDependencies, which depends on your webpack version.
If it does not solve your problem, paste your package.json file so i can get to know your webpack version.
Cheers.

Configure react webpack for deploy

need a little help.
We had tried to deploy a react project, but we are unable to configure it.
We use: es6, webpack, redux, react, babel.
this is webpack base:
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
export default {
entry: './app/app.js',
output: {
path: './app/App/dist',
filename: '/bundle.js',
},
module: {
loaders: [
{
test: /\.json$/,
loader: 'json',
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass'),
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('css!sass'),
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.svg$/,
loader: 'babel?presets[]=es2015,presets[]=react!svg-react',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './app/App/index.html',
}),
new ExtractTextPlugin('/app/App/css/default.css', {
allChunks: true,
}),
],
};
webpack dev:
import webpack from 'webpack';
import baseConfig from './webpack.config.base';
const config = {
...baseConfig,
debug: true,
devtool: 'cheap-module-eval-source-map',
plugins: [
...baseConfig.plugins,
new webpack.HotModuleReplacementPlugin(),
],
devServer: {
colors: true,
historyApiFallback: true,
inline: true,
hot: true,
},
};
export default config;
webpack prod:
import webpack from 'webpack';
import baseConfig from './webpack.config.base';
const config = {
...baseConfig,
plugins: [
...baseConfig.plugins,
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compressor: {
screw_ie8: true,
warnings: false,
},
}),
],
};
export default config;
This is our actual webpack, we are trying to deploy the project with it, but does not work.
Does anyone have an idea how to configure it?
So, it's a server problem probably. You need a HTTP server in order to server the static files (your app basically). I recommend the Ngxin, very easy to configure and use.
After install nginx, delete the /etc/nginx/sites-enable/default file and create a new one (you can use whatever name you want here). Here's the config I use:
server {
listen 80;
listen [::]:80;
server_name example.com;
location / {
root /var/html/myProject/;
try_files $uri /index.html;
}
}
after that, restart nginx and should be ready to go.
for webpack, I have a simpler config that works well:
const path = require("path");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isProd = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase() == 'production';
const plugins = [
new ExtractTextPlugin(isProd ? 'bundle.[hash].css' : 'bundle.css', { allChunks: true }),
new HtmlWebpackPlugin({
template: 'index.html',
inject: 'body',
filename: 'index.html'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
})
];
const prodPlugins = [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
];
module.exports = {
devtool: isProd ? 'cheap-module-source-map' : 'eval',
entry: [
'./src/index.jsx'
],
output: {
path: isProd ? path.join(__dirname, 'dist') : __dirname,
publicPath: '/',
filename: isProd ? 'bundle.[hash].js' : 'bundle.js'
},
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-1']
}
},
{
test: /\.(scss|css|sass)$/,
loader: ExtractTextPlugin.extract('css!sass')
},
{
test: /\.(png|woff|woff2|eot|ttf|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url'
},
{
test: /\.html$/,
loader: 'html'
}]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
},
plugins: isProd ? prodPlugins.concat(plugins) : plugins
};
A few points:
I'm using SASS
Check the path's before run anything
To compile for production, just run NODE_ENV=production webpack -p
I'm using a few plugins for Uglify JS and compress files.
I think that's it! Cheers!
sure I think the fastest way to solve your problem is to click on this link:
React starter kit
and select any starters that matches your technologies!
I think you are looking for this one : react-boilerplate

Specify destination folder in url-loader for webpack

I have images path in css like url(images/image1.jpg) and the loader is defined as
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/, loader: 'url-loader?limit=1&name=images/[name].[ext]' },
The issue I am facing is that after build process the images are copied to respective folder but the path is pointing to images/image1.jpg relative to the css file location. I want it to be relative to the root directory.
I tried adding a leading / in the name query parameter and it partially fixed the issue
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/, loader: 'url-loader?limit=1&name=images/[name].[ext]' },
but when I move my files into a sub folder it still points to the root of the domain instead of the folder.
Can you tell me what I am missing in the configuration?
Here is the webpack configuration
'use strict';
var webpack = require('webpack'),
HtmlWebpackPlugin = require('html-webpack-plugin'),
OpenBrowserPlugin = require('open-browser-webpack-plugin'),
ExtractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path'),
srcPath = path.join(__dirname, 'src'),
jsDestPath = 'scripts/';
module.exports = {
target: 'web',
cache: true,
entry: {
common: ['react', 'react-router', 'alt', 'es6-promise'],
offline: path.join(srcPath, 'libs/offline.min.js'),
materialize: path.join(srcPath, 'libs/materialize.js'),
css3_animate_it: path.join(srcPath, 'libs/css3-animate-it.js'),
app: path.join(srcPath, 'App.js')
},
resolve: {
root: srcPath,
extensions: ['', '.js'],
modulesDirectories: ['node_modules']
},
output: {
path: path.join(__dirname, 'build'),
publicPath: '',
filename: jsDestPath + '[name].js',
library: ['Example', '[name]'],
pathInfo: true
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel?cacheDirectory'
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
/*{
test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/,
loader: 'url-loader?limit=5' // inline base64 URLs for <=8k images, direct URLs for the rest
},*/
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/, loader: 'url-loader?limit=1&name=images/[name].[ext]' },
{
test: /\.rt/,
loader: "react-templates-loader"
}
],
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
}),
new webpack.optimize.CommonsChunkPlugin('common', jsDestPath + 'common.js'),
new webpack.optimize.UglifyJsPlugin({minimize: true}),
new HtmlWebpackPlugin({
inject: true,
template: 'src/index.html'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080',
browser: 'Chrome'
}),
new webpack.NoErrorsPlugin(),
new ExtractTextPlugin("styles/style.css", {
allChunks: true
})
],
debug: true,
//devtool: 'eval-source-map',//'eval-cheap-module-source-map',
devServer: {
contentBase: './build',
historyApiFallback: true
}
};
Remove publicPath: '', or set it to publicPath: '/', and require images
like this let imgSrc = require('../../img/image.png'); via relative paths(from where you are trying to require images).
It should get resolved as {publicPath}/images/[name].[ext]
I hope it should work.
You need to prefix your image URL with ~, otherwise it will be treated as relative to the CSS path. The ~ triggers webpack's normal module resolution. More info in the CSS loader docs here.

Resources