Configuring Webpack to required folder structure for build files - reactjs

I have a ReactJS application, that was built using Webpack. So, in my webpack.config.js, I have return the required code to take a build, and everything builds into a 'build' file, in my project folder.
This is the current file structure:
Project
| -- build
| -- index.html
| -- bundle.js
| -- background.png
| -- avatar.png
However, I want my build files to take a separate structure, as shown below:
Project
| -- build
| -- templates
| -- index.html
| -- static
| -- js
| -- bundle.js
| -- images
| -- background.png
| -- avatar.png
My webpack.config.js is provided below. I tried tweaking it, and the structure was obtained, but the images failed to load. The HTML and JS worked without any issues, but the images just didn't load. Shown below is the unaltered code, which builds all the files into a single folder.
const HtmlWebPackPlugin = require("html-webpack-plugin");
var path = require('path');
const htmlWebpackPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "index.html"
});
module.exports = {
entry: ["#babel/polyfill", './src/index.js'],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
devtool: "#eval-source-map",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.js?$/,
include: /(src[\/\\]js)/,
loader: 'babel-loader'
},
{
test: /\.jsx?$/,
include: /(src[\/\\]jsx)/,
loader: 'babel-loader'
},
{
test: /\.json?$/,
exclude: /(node_modules|bower_components)/,
loader: 'json-loader'
},
{
test: /\.css?$/,
loaders: ['style-loader', 'raw-loader']
},
{
test: /\.scss?$/,
loaders: ['style-loader', 'raw-loader', 'sass-loader', 'import-glob']
},
{
test: /\.(png|ico|gif)?$/,
loader: 'file-loader?limit=30000&name=[name].[ext]'
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
plugins: [htmlWebpackPlugin]
};

In your webpack.config.js, set your filename to static/js/bundle.js. This will output your bundle in a newly created build/static/js directory:
module.exports = {
// ...
output: {
filename: 'static/js/bundle.js',
path: path.resolve(__dirname, 'build')
},
// ...
}
Then set the outputPath property of file-loader to static/images/
// ...
{
test: /\.(png|ico|gif)?$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'static/images',
}
}
// ...

Related

Can I delete parts of bootstrap.min.css that I'm not using?

I have a small React app that I'm minifying with Webpack, and I noticed that ~80% of my minified index.js file is just Bootstrap css that I'm not using, plus Webpack warns me that my entry file is too big (~900kb vs ~250kb recommended). I found a few answers here from a long time ago that said to remove parts of bootstrap.min.css file that I don't need, and I'm wondering if that's still the recommended solution for a React app using react-bootstrap?
This is my production webpack config:
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
module.exports = {
entry: '/src/index.tsx',
output: {
path: path.resolve(__dirname, 'prod'),
},
mode: 'production',
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
},
},
},
{
test: /\.css$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules/react-toastify/dist'),
path.resolve(
__dirname,
'node_modules/bootstrap/dist/css/bootstrap.min.css'
),
path.resolve(
__dirname,
'node_modules/react-grid-layout/css/styles.css'
),
path.resolve(
__dirname,
'node_modules/react-resizable/css/styles.css'
),
],
use: ['style-loader', 'css-loader'],
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: 'ts-loader',
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
}),
new FaviconsWebpackPlugin('./src/logo.png'),
],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
}
And at the top of my App.tsx file I have
import 'bootstrap/dist/css/bootstrap.min.css'
Ok so I was able to (I think) accomplish what I was asking. I first tried to follow the instructions here:
https://medium.com/dwarves-foundation/remove-unused-css-styles-from-bootstrap-using-purgecss-88395a2c5772
So running purgecss --css [path to bootstrap css] ---content src/index.html --output public did create very minified CSS files, but either I did something wrong or purgecss removed too much, because the bootstrap styles didn't seem to be applied to anything.
Instead, I installed MiniCssExtractPlugin, and pointed webpack to the full bootstrap.min.css file. Running webpack with the below (updated) webpack.prod.js config file reduced the entry file size from ~900kb to ~360kb, which is still above the recommended limit but is about 1/3 the size of the entry before these changes.
Edit: and it also seems good that now the css styles are in their own actual main.css file, rather than for some reason being inside main.js, which is how it was before adding MiniCssExtractPlugin.
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: '/src/index.tsx',
output: {
path: path.resolve(__dirname, 'prod'),
},
mode: 'production',
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
},
},
},
{
test: /\.css$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'public')
],
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: 'ts-loader',
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
}),
new MiniCssExtractPlugin({filename: "[name].css", chunkFilename: "[id].css"}),
new FaviconsWebpackPlugin('./src/logo.png'),
],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
}

Why does %PUBLIC_URL% not get replaced in Webpack bundled index.html?

I am trying to deploy the front-end of my web application, but when I deploy to my hosting platform (currently AWS Amplify/S3) - no content displays on the website
I created the application using create-react-app, so the project structure follows their standard (public, src folders etc.).
When I run the application locally it works fine.
From the console errors, and looking at the index.html page that is generated by webpack, it looks like it is not replacing the %PUBLIC_URL% field that should be replaced with the public directory on build.
Please can someone explain how to fix this issue?
I have included my webpack.config file below and the full repo can be found here
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const config = {
entry: ['react-hot-loader/patch', './src/index.js'],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.svg$/,
use: 'file-loader',
},
{
test: /\.png$/,
use: [
{
loader: 'url-loader',
options: {
mimetype: 'image/png',
},
},
],
},
{
test: /\.(ttf|eot|woff|woff2)$/,
use: 'file-loader',
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'react-dom': '#hot-loader/react-dom',
},
},
devServer: {
contentBase: './build',
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve('./public/index.html'),
}),
],
}
module.exports = config
Turns out this was an issue with me trying to add a custom Webpack configuration to a create-react-app project.
I've removed the Webpack config now, and instead used the dist files created when using the create-react-app build process.

Cannot import semantic-ui-css

when I import the semantic ui react css module in my index.js file I get the following error.
ERROR in ./~/semantic-ui-css/themes/default/assets/fonts/brand-icons.svg
Module parse failed: C:\Users\dimal\Documents\Work\sample-app\node_modules\semantic-ui-css\themes\default\assets\fonts\brand-icons.svg Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <?xml version="1.0" standalone="no"?>
| <!--
| Font Awesome Free 5.0.8 by #fontawesome - https://fontawesome.com
# ./~/css-loader!./~/semantic-ui-css/semantic.min.css 7:196806-196862
# ./~/semantic-ui-css/semantic.min.css
# ./src/index.js
My webpack config is as following
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'index.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
exclude: /(node_modules|bower_components|build)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
},{
test: /\.(css|less)$/,
use: ["style-loader", "css-loader", "less-loader"]
}]
},
externals: {
'react': 'commonjs react'
}
};
What am I doing wrong in this?
The semantic UI CSS file has references to other files like images and fonts, so webpack has to have loaders for those types of files as well.
Ensure you have url-loader and file-loader packages installed and add these loaders to your webpack config:
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve("url-loader"),
options: {
limit: 10000,
name: "static/media/[name].[hash:8].[ext]",
},
},
{
test: [/\.eot$/, /\.ttf$/, /\.svg$/, /\.woff$/, /\.woff2$/],
loader: require.resolve("file-loader"),
options: {
name: "/static/media/[name].[hash:8].[ext]",
},
}
(you can change the folder path as you desire)

Failed to load template in truffle project

I am developing Dapp using Truffle v3.1.2 which is a development framework for Ethereum.I am using angular on node for this dapp & unfortunately I am very new to node & webpack.I am storing views in /views folder, images in /images folder & I need some help to modify the webpack.config.js file.I am using “npm run dev” to deploy it & I am getting “Error: [$compile:tpload] Failed to load template: views/main.html (HTTP status: 404 Not Found)” message.Please find the webpack.config.js file below.
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: [
'./app/bower_components/angular/angular.js',
'./app/bower_components/angular-route/angular-route.js',
'./app/javascripts/app.js',],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'app.js'
},
plugins: [
// Copy our app's index.html to the build folder.
new CopyWebpackPlugin([
{ from: './app/index.html', to: "index.html" }
])
],
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
],
loaders: [
{ test: /\.json$/, use: 'json-loader' },
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015'],
plugins: ['transform-runtime']
}
}
]
}
}

Error: output.path needs to be an absolute path or /

This is my webpack.config file. When I run webpack, bundle.js correctly writes to project/dist/assets/bundle.js.
However, when I run npm start to serve up the files, I get an error:
Error: output.path needs to be an absolute path or /.
So... if I make the path absolute: "/dist/assets" or path: __dirname + "/dist/assets" then it serves up the files fine, and emits bundle.js, but it doesn't actually write it to my project/dist/assets folder.
The page looks fine and when I view source, I see <script src="/assets/bundle.js"></script> but it only exists on the localhost (publicPath).
Where am I going wrong? The goal being for npm start to write the bundle to my project folder AND serve it up with devServer.
var webpack = require("webpack");
module.exports = {
entry: "./src/index.js",
output: {
path: "./dist/assets",
filename: "bundle.js",
publicPath: "/assets"
},
devServer: {
inline: true,
contentBase: "./dist",
port: 3000
},
module: {
loaders: [{
test: /\.js$/,
exclude: /(node_modules)/,
loader: ["babel-loader", "babel-loader?presets[]=latest,presets[]=stage-0,presets[]=react"]
}, {
test: /\.json$/,
exclude: /(node_modules)/,
loader: "json-loader"
}, {
test: /\.css$/,
loader: "style-loader!css-loader!autoprefixer-loader"
}, {
test: /\.scss$/,
loader: "style-loader!css-loader!autoprefixer-loader!sass-loader"
}]
}
}
Use path for this:
var path = require('path');
....
output: {
path: path.join(__dirname, './dist/assets'),

Resources