webpack-dev-server compiling very slow in rails app - ruby-on-rails-5

When I run
bin/webpack-dev-server
On a rails 5.1.7 application using react with react-rails gem, it can get stuck for more than 10-20 minutes with the message:
ℹ 「wdm」: wait until bundle finished: /packs/js/application-5bc097626fe492d88e56.js
My configuration is:
in erb.js
module.exports = {
test: /\.erb$/,
enforce: 'pre',
exclude: /node_modules/,
use: [{
loader: 'rails-erb-loader',
options: {
runner: (/^win/.test(process.platform) ? 'ruby ' : '') + 'bin/rails runner'
}
}]
}
in development.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
// Watch directories that often change the views.
// From: https://github.com/rails/webpacker/issues/1879#issuecomment-558397652
const chokidar = require('chokidar')
environment.config.devServer.before = (app, server) => {
chokidar.watch([
'config/locales/**/*.yml',
'app/views/**/*.html.erb',
'app/assets/**/*.scss'
]).on('change', () => server.sockWrite(server.sockets, 'content-changed'))
}
module.exports = environment.toWebpackConfig()

To speed up webpack-dev-server:
use javascript_packs_with_chunks_tag instead of javascript_pack_tag
add environment.splitChunks() to config/webpack/environment.js

I think it's probably because of rails-erb-loader which normally can take more than 10 seconds on build.
Try install speed-measure-webpack-plugin, it will help you to see what each step will take.
const environment = require('./environment')
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()
module.exports = smp.wrap(environment.toWebpackConfig())

Related

Webpack and Jquery - $ is not defined

Working first time on using Webpack in a ASP.Net Core project and running in to an issue bundling jQuery
$ is not defined
webpack.config.json
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const bundleFileName = 'bundle';
const dirName = 'wwwroot/dist';
module.exports = (env, argv) => {
return {
mode: argv.mode === "production" ? "production" : "development",
entry: ['./node_modules/bootstrap/dist/js/bootstrap.bundle.js', './wwwroot/js/site.js', './wwwroot/scss/site.scss'],
output: {
filename: bundleFileName + '.js',
path: path.resolve(__dirname, dirName)
},
module: {
rules: [
{
test: /\.s[c|a]ss$/,
use:
[
'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: bundleFileName + '.css'
})
]
};
};
I have tried and exhausted all possible variations I could find on the internet without any luck.
Using npm run build during the .Net build process to create the bundles
"$ is not defined" means that at the time when your library tried to do something with jQuery, jQuery itself either wasn't loaded or loaded incorrectly. Make sure that jQuery loads correctly first, and only then can the rest of the code use this library. Usually it is enough to put a jQuery call before all other calls.

How do you enable source maps in Webpack?

I want to enable source maps in my webpack.config.js. I'm adding onto some opensource and their webpack.config.js looks weird.
webpack.config.js
// Entry point webpack config that delegates to different environments depending on the --env passed in.
module.exports = function(env) {
process.env.NODE_ENV = env;
return require(`./webpack.${env}.js`);
};
Here is what it returns if env = development
/**
* Webpack configuration for development.
*
* Contains plugins and settings that make development a better experience.
*/
const webpack = require("webpack");
const merge = require("webpack-merge");
const fs = require("fs");
const { execSync } = require("child_process");
const path = require("path");
const argv = require("yargs").argv;
const commonConfig = require("./webpack.common.js");
const DashboardPlugin = require("webpack-dashboard/plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
if (!fs.existsSync(path.resolve(__dirname, "vendor", "vendor-manifest.json"))) {
// This _should_ exist, since we run the command for you when you run `npm run dev`
console.log(
"Vendor files not found. Running 'npm run build:dev-dll' for you..."
);
execSync("npm run build:dev-dll");
console.log("Done generating vendor files.");
}
const devConfig = {
mode: "development",
main: {
devtool: "source-map",
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify("development")
}),
new webpack.DllReferencePlugin({
context: ".",
manifest: require("./vendor/vendor-manifest.json")
}),
new ForkTsCheckerWebpackPlugin({
tslint: true,
async: false,
silent: true
})
]
}
};
// Only enable the dashboard plugin if --watch is specified
// The dashboard plugin annoyingly doesn't allow webpack to exit,
// so we only enable it with --watch, which doesn't exit anyways
if (argv.watch) {
devConfig.main.plugins.push(new DashboardPlugin());
}
module.exports = merge.multiple(commonConfig, devConfig);
I don't know if source map should be added to webpack.config.js or maybe just the development version and I don't know how to add it cause these config files look odd to me.
The line... "devtool": "source-map" is correct, but it appears to be at the wrong depth.
Should be:
const devConfig = {
mode: "development",
devtool: "source-map",
main: {
...
}
};

Different variable value in Vue.js + Webpack in dev server vs build

I'm working on a Vue.js project which is running Webpack in local development & builds static files for deployment.
There is a variable apiDomain which needs to change from:
http://localhost.api/ - in local development
to
https://api.example.com/ - in the static build files
I've been trying to get my head around environmental variables but I'm not sure how they work in Webpack vs Vue.js.
What is the correct way to setup a Vue.js variable so it's different between local development & the static build files?
You can adapt this idea for your needs:
import axios from "axios";
const env = process.env.NODE_ENV || "development";
console.log(`we are on [${env}] environment`);
const addr = {
production: "https://rosetta-beer-store.io",
development: "http://127.0.0.1:3000",
};
const api = axios.create({
headers: {"x-api-key": "my-api-key", "x-secret-key": ""},
baseURL: addr[env],
});
export const beerservice = {
list: params => api.get("/beer/list", {params}),
find: id => api.get(`/beer/${id}`),
};
export const mediaservice = {
url: id => (id ? `${addr[env]}/media/${id}` : `${addr[env]}/icon.svg`),
};
By using the process.env.NODE_ENV (available on development and build time) you can not only to set the correct profile for the app services endpoints but also manage any tweak you need on your build scripts:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");
module.exports = {
mode: process.env.NODE_ENV || "development",
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.html$/,
loader: "html-loader"
},
{
test: /\.(png|svg|jpg|gif|woff|woff2|eot|ttf|otf)$/,
use: ["file-loader"]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"]
}
]
},
resolve: {
extensions: ["*", ".js", ".jsx"]
},
entry: "./src/main.jsx",
output: {
filename: "build.js",
path: path.resolve(__dirname, "dist")
},
devtool:
process.env.NODE_ENV == "development" ? "inline-source-map" : undefined,
devServer: {
contentBase: "./dist",
hot: true
},
plugins: [
new CleanWebpackPlugin(["dist"]),
new HtmlWebpackPlugin({
template: "./index.html"
}),
new webpack.HotModuleReplacementPlugin()
]
};
You can see more examples on this github project, but the general idea is to take advantage of node at the build time

Is it possible to use antd with create-react-app 2?

My understanding is react-app-rewired no longer works in v2 of create-react-app.
It seems you need to get into babel (thus react-app-rewired).
You can use craco instead of react-app-rewired.
Information from react-app-rewired issue comments:
Here are some example craco.config.js configuration files:
Less
Ant Design + Less + modifyVars
Ant Design + Less + modifyVars + Preact
Preact
There are some more examples in the /recipes directory in the craco repo.
Example of craco.config.js from ndbroadbent:
const CracoAntDesignPlugin = require('craco-antd');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const WebpackBar = require('webpackbar');
module.exports = {
webpack: {
alias: { react: 'preact-compat', 'react-dom': 'preact-compat' },
plugins: [
new BundleAnalyzerPlugin(),
new WebpackBar({ profile: true }),
],
},
plugins: [{ plugin: CracoAntDesignPlugin }],
};

Webpack dev middleware react hot reload too slow

I have a simple configuration with webpack-dev-middleware and webpack-hot-middleware that uses Hot reload (HMR) with react.
Everything is working fine except that every change i made to the code it takes up 2 3-4 seconds !!! till I see it in the browser.
Am I doing something wrong ? it's supposed to be like this ?
My code is rather big and my bundle minified get to 841kb (200kb gzipped) is this the reason ? the more the codebase is bigger the bundle creation in slower?
Express Server:
var webpack = require('webpack');
var webpackConfig = require('./webpack.hot.config');
var compiler = webpack(webpackConfig);
app.use(require("webpack-dev-middleware")(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath,
watchOptions: {
poll: true
}
}));
app.use(require("webpack-hot-middleware")(compiler, {
log: console.log,
path: '/__webpack_hmr',
heartbeat: 10 * 1000
}));
webpack.hot.config.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: __dirname,
entry: [
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000',
'./src/js/index'
],
module: {
loaders: [{
test: /\.jsx?$/,
include: path.join(__dirname, 'src/js'),
//exclude: /node_modules/,
loader: 'react-hot!babel'
},
{
// Test expects a RegExp! Note the slashes!
test: /\.css$/,
loaders: ['style', 'css'],
// Include accepts either a path or an array of paths.
include: path.join(__dirname, 'src/css')
}
]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
output: {
path: __dirname + '/public',
publicPath: '/',
filename: 'js/app.js'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
};
And this is what i get in the console when i changed something in the code:
[HMR] App is up to date.
app.js:73223 [HMR] bundle rebuilding
app.js:73226 [HMR] bundle rebuilt in 335ms
app.js:73289 [HMR] Checking for updates on the server...
app.js:73362 [HMR] Updated modules:
app.js:73364 [HMR] - ./src/js/components/header.jsx
app.js:73369 [HMR] App is up to date.
Pro Tip: Change your mode in webpack.config.js to development. It defaults to production if you leave this property out, which means it does slow production stuff and makes your hot reloading suck.
module.exports = {
mode: 'development'
};
Consider switching polling to false in your middleware. I've found that polling can be CPU-intensive.
In you webpack config, you might also want to try adding devtool: false to avoid creating a source map.
You should enable caching:
...
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
cache: true
};