I'm lately trying to dockerize my react app to learn docker.
I'm using weback for managing this project.
Now here is the thing, after I run dev script npm run dev, server gets on, but I'm not able to connect to it either on host (posting container on 3000:3000) and inside container for any-given ports that came up to my mind (like 8000, 8080, 3000, 5000). It just seems to me like the port connection is not set up properly.
Reading some webpack docs did not give me any clue.
The questions are: best way to define server scripts to run ?
My way of doing it is:
"scripts": {
"dev": "webpack --mode development --watch",
"build": "webpack --mode production"
},
Is there any default-like port that webpack sets its connection to (maybe a way to change it)?
What I did establish, is that for 90% it's my webpack config. After dockerizing react app with create-react-app I did have successfull start.
My webpack.config.js :
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: { index: path.resolve(__dirname, "src", "index.js") }, //"./src/index.js",
output: {
path: path.resolve(__dirname, "./static/frontend"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
optimization: {
minimize: true,
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("production"),
},
}),
],
};
Related
I am in middle of optimising my react app bundle. Current size is 1.4MB. Implemented Lazy loading in routers. While running the app at localhost, i can see lazy loading working well in Network tab of browser, I see first initial chunk loads and render's in the browser then rest of the 1.4MB comes. Problem comes when i create a production bundle and deploy it to server, there entire 1.4MB loads and then can see rendering.
Is there something missing during production bundle creation? How to check if lazy loading is working from server?
Webpack.config.js
const path = require('path');
const { resolve } = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
var CompressionPlugin = require('compression-webpack-plugin');
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
module.exports = {
devtool: 'cheap-module-source-map',
entry: './src/index.jsx',
resolve: {
fallback: { crypto: false },
extensions: ['.js', '.jsx', '.json', '.wasm'],
enforceExtension: false,
alias: {
process: resolve('node_modules/process')
}
},
devServer: {
historyApiFallback: true,
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$|jsx/,
loader: 'babel-loader',
exclude: /node_modules[/\\\\](?!(mesh-component-library|mesh-icon-library)[/\\\\]).*/
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
]
},
{
test: /\.sass$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'images/[hash]-[name].[ext]'
}
}
]
}
]
},
plugins: [
new webpack.ProvidePlugin({ process: 'process/browser' }),
new HtmlWebpackPlugin({ template: './public/index.html' }),
new MiniCssExtractPlugin({ filename: 'styles.css' }),
new webpack.EnvironmentPlugin({
NODE_ENV: process.env.BABEL_ENV,
BABEL_ENV: process.env.NODE_ENV
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new CompressionPlugin({
algorithm: "gzip",
threshold: 10240,
minRatio: 0.8
})
]
};
Package.json
"scripts": {
"test": "jest --watchAll=false --coverage",
"testWithResults": "jest --json --outputFile=./testResults.json",
"start": "webpack-dev-server --mode development --config webpack.config.js --open --port 4000",
"build": "webpack --mode production --config webpack.config.js",
"eslint": "eslint src/**/*.js*"
},
Try configuring webpack SplitChunksPlugin to include all.
Add this section to your webpack config.
optimization: {
splitChunks: {
chunks: 'all',
}
}
I would suggest using the Webpack bundle analyzer, it has helped me differentiate between bundle sizes before and after implementing dynamic loading recently. The implementation is quite simple, they've mentioned it in the docs. It's easy to understand the differences in size as well as everything is visual. Hope this helps!
I am trying to setup the environment so that when i choose to run prod it runs the prod settings and when i choose to run dev it runs the dev server, currently my package.json scrips look like this :
"scripts": {
"build:dev": "cross-env NODE_ENV=developement webpack",
"build:prod": "cross-env NODE_ENV=production webpack",
"start:dev": "cross-env NODE_ENV=developement webpack-dev-server ",
"start:prod": "cross-env NODE_ENV=production webpack-dev-server "
},
webpack config file:
const webpack = require("webpack");
const path = require("path");
const dotenv = require("dotenv");
module.exports = {
//Entry file for webpack.config
entry: "./src/index.js",
//Target specific use of project ie. nodejs project we use node value
target: process.env.NODE_ENV === "dev" ? "node" : "web",
//Dev server meant for hosting local server for developement
devServer: {
contentBase: path.resolve(__dirname, "public"),
historyApiFallback: true,
port: 8080,
},
//Modules are used to set rules to build specific file types
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: ["#babel/env", "#babel/react"],
plugins: [
"#babel/plugin-transform-runtime",
"#babel/plugin-proposal-class-properties",
],
},
},
],
},
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
{
test: /\.(css|sass|scss)$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
sourceMap: true,
importLoaders: 2,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
},
{
test: /\.svg$/,
use: [
{
loader: "svg-inline-loader",
options: {
limit: 10000,
},
},
],
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
externals: {
// require("jquery") is external and available
// on the global var jQuery
"jquery": "jQuery"
},
//Changes how modues are resolved
resolve: {
extensions: ["*", ".js", ".jsx", ".ts", ".tsx"],
},
//Output is setup to serve the bundle.js file to be served to web browser
output: {
path: path.resolve(__dirname, "public"),
filename: "bundle.js",
publicPath: "/",
},
//Prevent bundling of certain packages
externals: {
"react-native": true,
},
//A javascript object used to do various extra things for webpack
plugins: [
new webpack.DefinePlugin({
"process.env": JSON.stringify(dotenv.config().parsed),
}),
],
};
and i do:
console.log(process.env.NODE_ENV)
inside my homepage jsx, but everytime I run it even when i do yarn start:prod it console.logs development and not production, why is cross-env not successfully changing the NODE_ENV to production when i run this?
In order to copy env variable into webpack, you have to use webpack. DefinePlugin as you have done in your configuration file which looks like you're trying to copy all things into webpack.
Anyway if you want to use the value from cross-env, you would have do the same thing by using DefinePlugin plugin but input the specific value NODE_ENV as following:
webpack.config.js
{
// ...
plugins: [
// ...
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
],
}
I have been trying to make React app development easier by using reloading of the app when I modify the files and I tried webpack-dev-server for that (Please, see my previous thread: Can't set up webpack-dev-server to start React app). I made hot reloading working but got an issue: timeouts started to occur on my requests and I see the empty response errors in console. There are threads that discuss the issue, e.g.: https://github.com/webpack/webpack-dev-server/issues/183
but so far I could not make it working. Setting --host 0.0.0.0 is not working, setting --port 3000 eliminates empty response error but hot reloading is gone... Below is my webpack relevant config:
devServer: {
index: '',
open: true,
proxy: {
context: () => true, // endpoints which you want to proxy
target: 'http://localhost:3000' // your main server address
}
},
entry: {
app: ['babel-polyfill', './views/index.js']
//vendor: ["react","react-dom"]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './public')
},
devtool: "#eval-source-map",
...
I am starting the app by running npm run dev, here is a part of the package.json:
"scripts": {
"client": "webpack-dev-server --mode development --devtool inline-source-map --port 3000 --content-base public --hot",
"server": "node ./bin/www",
"dev": "concurrently \"npm run server\" \"npm run client\"",
},
So, above if we remove --port 3000 hot reloading on the front end part starts working, but then the timeout is happening. Also, upon modification of the server side code the app is not reloaded unfortunately and I am not sure how to add this feature too. I am using react-hot-loader:
import React from 'react';
import ControlledTabs from './ControlledTabs'
import { hot } from 'react-hot-loader/root'
class App extends React.Component {
render() {
return (
<ControlledTabs/>
);
}
}
module.exports = hot(App);
I think it should be related to the devServer configs most probably and how the webpack-dev-server is started. I just want to find a WORKING way of doing hot reloading instead of falling back into build - run cycle that is annoying and inefficient.
Also, it is really hard to say, what is going wrong, whether --port 3000 is really the issue. I noticed that the webpack-dev-server is somehow working in a very unpredictable way on my project meaning that after doing changes and launching the app I see one result, but then I restart webpack-dev-server and see a different result as if webpack-dev-server is doing something behind the scenes what it wants to and whenever it wants to without notifying me about that.
Update
I changed webpack.config.js to:
watch: true,
devServer: {
index: '',
open: true,
proxy: {
context: () => true, // endpoints which you want to proxy
target: 'http://localhost:3000' // your main server address
}
},
entry: {
app: ['babel-polyfill', './views/index.js']
//vendor: ["react","react-dom"]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './public')
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
And removed react-hot-loader from the React entry point:
import React from 'react';
import ControlledTabs from './ControlledTabs'
class App extends React.Component {
render() {
return (
<ControlledTabs/>
);
}
}
module.exports = App;
Because otherwise it was giving me a syntax error in console, webpack could not start. After doing that if I modify any react file, whole webpage is reloaded it seems and the net::ERR_EMPTY_RESPONSE remains...
Add a watch to your webpack config.
watch: true
Also, you need to enable module replacement loading within the webpack dev server.
In short, if you see how this config is setup, this is a working example of hot reloading for a very basic react app. It uses ExpressJS as well.
https://github.com/chawk/bare_bones_react/blob/master/webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const express = require('express');
module.exports = {
entry: {
app: './src/index.js'
},
devServer: {
hot: true,
compress: true,
contentBase: path.join(__dirname, 'dist'),
open: 'Chrome',
before(app) {
app.use('/static', express.static(path.resolve(__dirname, 'dist')))
}
},
devtool: 'source-map',
output: {
filename: './js/[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: './server/index.html'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
},
resolve: {
extensions: [
'.js'
]
}
}
I am trying to use Hot Loader. I have installed Hot Loader and followed all the steps from the documentation http://gaearon.github.io/react-hot-loader/getstarted/. I then give "npm start" command to the terminal. But terminal throws an error. I am not able to see the changes I make in the component getting reflected in browser.
webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
devServer: {
inline: true,
contentBase: './src',
port: 3000
},
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-dev-server/client?http://localhost:3000', // WebpackDevServer host and port
'webpack/hot/only-dev-server', // "only" prevents reload on syntax errors
'./dev/js/index.js' // Your appʼs entry point
],
module: {
loaders: [
{
test: /\.js$/,
loaders: ['react-hot','babel'],
exclude: /node_modules/
},
{
test: /\.scss/,
loader: 'style-loader!css-loader!sass-loader'
}
]
},
output: {
path: 'src',
filename: 'js/bundle.min.js'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.OccurrenceOrderPlugin()
]
};
Script part of Package.json
"scripts": {
"dev": "webpack",
"start": "node server.js"
},
server.js
var webpack = require('webpack');
var webpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
var port = 3000;
var compiler = webpack(config);
new webpackDevServer(compiler, {
publicPath: config.output.publicPath,
hot:true,
stats:{colors:true}
}).listen(port, 'localhost', function (err, result) {
if(err){
console.log(err);
}
console.log('listening at localhost' + port);
});
Few quetions
1. Is my server.js file is fine.
2. Have I included everything correctly in scripts in package.json.
3. Is "npm start" a command to launch hot loader.
4. Even after getting error after "npm start", I can launch my application
in the browser by clicking the chrome icon. What is the reason.
5. What should I change in these files to get a working hot loader.
I have a ReactJs ES6 (ie 'import' keywords) app that uses gulp for generating a physical build file and webpack for hot-loading the changes to a virtual file. I wanted to combine the two services with npm start (which current loads webpack, not gulp).
server.js file
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true
}).listen(3000, 'localhost', function (err, result) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:3000');
});
webpack.config.js file
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/index.js'
],
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'build'),
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [{
test: /\.jsx?$/,
loaders: ['react-hot', 'babel-loader'],
include: path.join(__dirname, 'src'),
exclude: /node_modules/
},
{ test: /\.css$/, loader: 'style-loader!css-loader' }
]
}
};
I thought based on webpack's output section, webpack would generate a physical file in my build folder while creating a virtual file in '/static/bundle.js'
Currently, the virtual file with hot-loader is working, but no physical file has been built in the 'build' path.
Am I correct that webpack can replace gulp and generate both a physical & virtual build file? If so, where is my code in err as far as creating a physical build file?
Thanks in Advance.
Solution:
My code is fine, I needed to add to my scripts in package.json:
.....
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"gulp": "gulp",
"all": "npm run build && npm run gulp"
.....
I then run "npm run all" and I can run webpack and gulp from one command