react scripts build generate new hash even if the code not changes - reactjs

I build react app without create-react-app (without eject).
I want to generate new hash every build if the code not change (because cache issue).
I installed react-app-rewired for using config overloads and change package.json to
"build": "react-app-rewired build",
in config-overrides.js I'm trying to create new hash for each build (minified, css, js,styled and etc) but not sure I do it in right way
require('dotenv').config();
var uniqid = require('uniqid');
const FileManagerPlugin = require('filemanager-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
webpack: function (config, env) {
console.log('outputconfig before', config.output);
const buildHash = uniqid();
config.output.filename = `static/js/[name].${buildHash}.js`;
config.output.chunkFilename = `static/js/[name].${buildHash}.chunk.js`;
console.log('outputs config', config.output);
return config;
},
};
when I deploy it to production it looks like the hash build is the same if the code has not changes.. not sure if I configure the config-overloads.js right, maybe I need to add webpack or something not sure.
I want every build to generate new unique name to js, css and html files.

If the input is the same, if you did not change anything in the codebase, webpack will ALWAYS produce the same hash. This is the main property of a hash function. So you have to somehow always change the codebase. To achieve this you can write to a js file and import it in app.js so webpack will see that file's input has changed. In your webpack.config.js
const crypto = require("crypto");
const fs = require("fs");
const content = crypto.randomBytes(8).toString("hex");
const value = JSON.stringify(content);
// we have to write a valid javascript
fs.writeFile("src/test.js", `export const a=${value}`, (err) => {
if (err) {
console.error(err);
}
});
this test.js has no effect on your code. So you could safely import in app.js
import "./test.js";
If you dont import it will not work. Because webpack will read only imported code.
in webpack.config.js i defined the filename like this
output: {
filename: "[name].[hash].js",
path: path.join(__dirname, "dist"),
publicPath: "/",
},
every time I run npm run build it creates a different hash. Proof of work:

Related

How to configure the start script in webpack to use the api I want?

How to configure the start script in webpack to use the api I want?
For example when I run "npm start" my webpack source will use the productuion api like 'https://abc_loginapi.com, and when I run "npm run dev" the webpack source Mine will use local apis like http://localhost:9500/login.
My current way of doing it is quite manual, when I want to run one, I will comment the other one
export const API_HOST_LIST =
{
HostBaseURL: 'https://abc_loginapi.com'
// HostBaseURL: 'http://localhost:9500/login'
}
Is there any way to handle this problem, my source is webpack4 + reactJS
You can use environment variables to handle it, add env to script with --env argument, like this:
webpack --env prod // result { prod: true }
And call it in webpack config file
const path = require('path');
module.exports = env => {
// Use env.<YOUR VARIABLE> here:
console.log('Production: ', env.prod); // true
return {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
};
For more detail, check Webpack docs here
Like Phr0gggg mentions, using environment variables is one option.
Another option is to use the "NODE_ENV" variable.
In dev mode, process.env.NODE_ENV is equal to 'development' and in production, it's equal to 'productoin'
And you can use something like this:
const isProduction = process.env.NODE_ENV === "production"
const hostBaseUrl = () => {
if (isProduction) {
return 'http://localhost:9500';
}
return 'https://abc_loginapi.com';
}
export const API_HOST_LIST =
{
HostBaseURL: hostBaseUrl()
}
You can use process.env api to judge in webpack,
The code in webpack file like.
export const API_HOST_LIST =
{
HostBaseURL: process.env.NODE_ENV ==='dev'? 'http://localhost:9500/login':'https://abc_loginapi.com'
}
The code in package.json file like.
"scripts": {
"dev": "NODE_ENV=dev npm run start",
"start": "npm start"
}

import "!babel-loader!mdx-loader!foo.mdx" not working with react-scripts#5.0.0

Trying to upgrade an existing React project from react-scripts#4 to #5.0.0 fails for importing transpiled MDX sources.
/* eslint import/no-webpack-loader-syntax: off */
import AboutMDX from "!babel-loader!mdx-loader!./About.mdx"
AboutMDX does not receive an MDXComponent but instead now as of react-scripts 5 end up with a string which is the path name of the transpiled javascript source code file. How can I fix this change in behavior to correctly import the MDXComponent?
This has been an od(d)ysee because the whole MDX2+CRA5+remark/rehype ecosystem is prone to breakage in my experience. While MDX documents to use CRACO7 with CRA5, the MDX project when kindly asked points fingers to CRACO and wasn't helpful to me in getting me over ES modules and CSJ hurdles in order to finally get the pieces to work. While the following now works for me (at the moment) I don't know how robust this set up actually is.
upgrade to CRA 5
install CRACO 5
make sure to call the craco command instead of react in your package.json scripts.
make sure to clean up your (stale) dependencies.
add these dependencies and dev dependencies:
"#mdx-js/loader": "^2.2.1",
"#mdx-js/mdx": "^2.2.1",
"#mdx-js/react": "^2.2.1",
"#types/mdx": "^2.0.3",
"#craco/craco": "^7.0.0",
"#craco/types": "^7.0.0",
if in the past you had a declare module '*.mdx {...}' in a src/index.d.ts then remove this now completely, as it would conflict with what comes with the MDXv2 loader.
remove !babel-loader!mdx-loader! from all your *.mdx imports. Do not use !#mdx-js/loader! etc. either, as the webpack configuration below will take care of the preprocessing.
create a craco.config.js as follows; this is a more elaborate configuration that shows how to actually pull in ES modules with CRACO 5 still not supporting ESM in their configuration, but requiring to go through the dynamic import with delayed configuration setup hurdles:
const { addAfterLoader, loaderByName } = require('#craco/craco')
module.exports = async (env) => {
const remarkGfm = (await import('remark-gfm')).default
const remarkImages = (await import('remark-images')).default
const remarkTextr = (await import('remark-textr')).default
const rehypeSlug = (await import('rehype-slug')).default
const textrTypoApos = (await import('typographic-apostrophes')).default
const textrTypoQuotes = (await import('typographic-quotes')).default
const textrTypoPossPluralsApos = (await import('typographic-apostrophes-for-possessive-plurals')).default
const textrTypoEllipses = (await import('typographic-ellipses')).default
const textrTypoEmDashes = (await import('typographic-em-dashes')).default
const textrTypoEnDashes = (await import('typographic-en-dashes')).default
return {
webpack: {
configure: (webpackConfig) => {
addAfterLoader(webpackConfig, loaderByName('babel-loader'), {
test: /\.(md|mdx)$/,
loader: require.resolve('#mdx-js/loader'),
/** #type {import('#mdx-js/loader').Options} */
options: {
remarkPlugins: [
remarkGfm,
remarkImages,
[remarkTextr, {
plugins: [
textrTypoApos,
textrTypoQuotes,
textrTypoPossPluralsApos,
textrTypoEllipses,
// textrTypoEmDashes,
textrTypoEnDashes,
],
options: {
locale: 'en-us'
}
}],
],
rehypePlugins: [
rehypeSlug,
],
}
})
return webpackConfig
}
}
}
}

How to read appsettings.json file using webpack.config or tsconfig.json in .net-core react redux project?

I am setting up .net-core with a react-redux project in VS 2017. I removed default CleintApp and created a new folder with "npm create-react-app --typescript".
Here are multiple questions
Where I can find webpack.config.json file
How can I read appsettings.json file using webpack.config file to import third party library URL which is set in appsettings.json
appsettings.json
{
"menuUrl": "",
"apiUrl": "",
}
Now I want to read menuURL and import in webpack?
Add
const appsettings = require('./appsettings.json');
Then use it as follows:
appsettings.menuUrl;
Example
const webpack = require('webpack');
const appsettings = require('./appsettings.json');
module.exports = env => {
var version = appsettings.AppSettings.AppVersion;
var lastIndex = version.lastIndexOf(".");
var majorMinorVersion = version.substring(0, lastIndex);
...
return {
entry: {
app: './ElmMobile/index.js'
},
...

How to use "webpack.DefinePlugin" with React Gatsby and React-Bodymoving?

I am pretty new to React but I want to set
BODYMOVIN_EXPRESSION_SUPPORT in Webpack's Define plugin with Gatsby v1.
I followed the links below but I don't get what exactly I suppose to do...
https://github.com/QubitProducts/react-bodymovin
https://www.gatsbyjs.org/docs/environment-variables/
I made the file named .env.development and put it to src folder. the content in this file is below.
plugins: ([
new webpack.DefinePlugin({
BODYMOVIN_EXPRESSION_SUPPORT: true
})
])
The folder structures is
root--
|
|- public //where the build goes
|
|- src -- //where I develop site
|-components
|-data
|-pages
|-style
|-.env.development
What I noticed is there is a line said
/*global BODYMOVIN_EXPRESSION_SUPPORT*/
in bodymovin library and I think I just need to change that. I could modify in library directly maybe but I don't think that a best way to get around this problem. Does someone know how to set this up right?
Thanks in advance!
EDIT 2019-09-02
To use environment variables from .env files I recommend using dotenv because it's so simple. Here's an example that creates an object of all the variables in the .env file and makes them accessible on the client side (i.e in React) through DefinePlugin.
// gatsby-node.js
var dotenv = require('dotenv');
const env = dotenv.config().parsed;
// Create an object of all the variables in .env file
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
exports.onCreateWebpackConfig = ({ stage, rules, loaders, plugins, actions }) => {
actions.setWebpackConfig({
plugins: [
// Add the environment variables to webpack.DefinePlugin with define().
plugins.define(envKeys)
]
});
};
Here's an example of how I get the application name and version from package.json and using it in my service worker, I'm using Gatsby V2 though. Having the version in the service worker makes caching easier to handle. As you wrote, DefinePlugin is the way to go but it's a bit different when we use it in Gatsby.
We need to import the package.json file and add our custom webpack configuration in gatsby-node.js, with plugins.define() we tell webpack to use DefinePlugin:
const packageJson = require('./package');
exports.onCreateWebpackConfig = ({
plugins,
actions,
}) => {
actions.setWebpackConfig({
plugins: [
plugins.define({
__NAME__: JSON.stringify(packageJson.name),
__VERSION__: JSON.stringify(packageJson.version),
}),
],
})
}
The two defined variables __NAME__ and __VERSION__ are now accessible in my service worker sw.js:
self.addEventListener('install', function (e) {
// eslint-disable-next-line
console.log(__NAME__, __VERSION__);
e.waitUntil(
caches.open(__NAME__ + __VERSION__).then(function(cache) {
return cache.addAll(filesToCache);
})
);
});
Gatsby Reference: https://www.gatsbyjs.org/docs/add-custom-webpack-config/

Setting up babel-plugin-styled-components + Typescript + create-react-app

We are currently trying to integrate the babel-plugin-styled-components into our typescript and create-react-app based setup for a better debugging experience and we are having difficulties doing so.
We are reluctant to eject the app, which is why we are trying to set it up using react-app-rewired and we also managed to get our typescript code to compile using react-app-rewire-typescript along with react-app-rewire-styled-components.
For some reason however, the displayName is not applied, which makes me think the babel plugin is not applied.
We are using "start": "react-app-rewired start" as our dev server script and the config-overrides.js looks like this:
const rewireTypescript = require('react-app-rewire-typescript');
const rewireStyledComponents = require('react-app-rewire-styled-components');
module.exports = function override(config, env) {
return rewireTypescript(rewireStyledComponents(config, env), env);
}
I have no idea what we are missing. Swapping the encapsulation of the rewire... functions also didn't help.
Does anyone here have experience with that or can point me in the right direction?
If you are using webpack, I found a solution that did not require using babel.
https://github.com/Igorbek/typescript-plugin-styled-components
To use it, you add a custom transform to your typescript loader with webpack:
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader',
options: {
getCustomTransformers: () => ({ before: [styledComponentsTransformer] })
}
}
This solves the displayName not showing when using styled-components and typescript.
I solved the issue by add something like this in config-overrides.js using react-app-rewired:
const createStyledComponentsTransformer = require('typescript-plugin-styled-components').default;
const styledComponentsTransformer = createStyledComponentsTransformer();
module.exports = function override(config, env) {
const rule = config.module.rules.filter(l => l.oneOf)[0];
const tsLoader = rule.oneOf.filter(l => String(l.test) === String(/\.(ts|tsx)$/))[0];
tsLoader.use[0].options.getCustomTransformers = () => ({
before: [styledComponentsTransformer]
});
return config;
}

Resources