Webpack obfuscator not working with craco, maps disabled - reactjs

today I have a very large problem using react & craco, I can't seem to get my webpack-obfuscator to do anything. I have disabled source maps, but to no avail.
This is my craco config:
const path = require("path");
const WebpackObfuscator = require('webpack-obfuscator');
module.exports = {
webpack: {
configure: (webpackConfig) => {
// Because CEF has issues with loading source maps properly atm,
// lets use the best we can get in line with `eval-source-map`
if (webpackConfig.mode === 'development' && process.env.IN_GAME_DEV) {
webpackConfig.devtool = 'eval-source-map'
webpackConfig.output.path = path.join(__dirname, 'build')
}
return webpackConfig
},
plugins: {
add: [
new WebpackObfuscator ({
rotateStringArray: true
}),
],
},
},
devServer: (devServerConfig) => {
if (process.env.IN_GAME_DEV) {
// Used for in-game dev mode
devServerConfig.writeToDisk = true
}
return devServerConfig
}
}
I get no visible maps files when building, and I've put "GENERATE_SOURCEMAP=false" in my .env file that's located where the package.json is.
Hopefully someone has the answer as to why this is happening.
Kind regards, and thanks for reading.

To upgrade a short config, you can use a construct that, if the condition is met, updates the configuration without using WebpackObfuscator:
module.exports = {
webpack: {
configure: {
...(process.env.IN_GAME_DEV && process.env.NODE_ENV === 'development' && {devtool: 'eval-source-map'})
}
}
}
Also, if you need additional properties for the configuration, in addition to the dvttool, you can add them

Related

How to add typescript paths to storybook

I have a react application with a custom Webpack configuration.
After adding Webpack aliases that matches tsconfig.json file compilerOptions->paths field the aliases were recognized by webpack.
Since storybook comes with a built in Webpack configuration, my aliases are not read by Storybook and I'm getting the following error:
Module not found: Error: Can't resolve <path with typescript alias> in <some folder path>
In Storybook main.js file, add the following:
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
...,
webpackFinal: async (config, { configType }) => {
config.resolve.plugins = [new TsconfigPathsPlugin()];<-- this line
return config;
}
};
You can install tsconfig-paths-webpack-plugin using the following command from the folder in which your application's package.json file resides:
npm i tsconfig-paths-webpack-plugin -D
Solution was derived from this discussion:
https://github.com/storybookjs/storybook/issues/6316
For future vistors of this question, since 15th July of 2022 storybooks can use Vite instead Webpack.
In that case I recommend using vite-tsconfig-paths instead of tsconfig-paths-webpack-plugin. If you are using TS paths in Vite, you probably already have this package installed.
Add this to your .storybook/main.js
const { mergeConfig } = require("vite")
const { default: tsconfigPaths } = require('vite-tsconfig-paths')
module.exports = {
// your previous configs and more...
viteFinal(config, { configType }) {
return mergeConfig(config, {
plugins: [
tsconfigPaths()
]
})
}
}
An alternative to accepted solution:
If you prefer not to install an external library such as tsconfig-paths-webpack-plugin, you can create a custom file, say:
tsconfig-webpack-utils.js
and do something similar to the following:
const { compilerOptions } = require('../tsconfig.json');
function getAliases() {
const baseUrl = getTSBaseUrl();
return Object.fromEntries(Object.entries(compilerOptions.paths).map(([key, value]) => {
return [
key.replace(/\/\*\*?$/,''),
value.map(entryPath => path.resolve(__dirname, baseUrl, entryPath.replace(/\/\*\*?$/,'/')))
]
}));
}
function getTSBaseUrl() {
return path.resolve(__dirname, `../${compilerOptions.baseUrl}`);
}
exports.addTsDefinitionsToWebpack = function(webpackConfig) {
if (!webpackConfig.resolve.modules) {
webpackConfig.resolve.modules = ['node_modules'];
}
webpackConfig.resolve.modules.push(getTSBaseUrl());
webpackConfig.resolve.alias = {
...webpackConfig.resolve.alias,
...getAliases()
};
}
This solution only works for very simple aliases. It is recommended to use an appropriate library or to expand this solution according to your needs.
You can then use it as follows in every webpack config you require it:
addTsDefinitionsToWebpack(webpackConfig);

How to set buildId to config (publicRuntimeConfig) or environment variable?

We're using nextjs (9.5.3) and next-i18next (6.0.3) for translations. To implement a special caching, I need to access the build ID outside of next.config.js in i18n.js in order to set it to the locale path:
localePath: path.resolve(`./public/static/cache/${config.buildId}/locales`)
In next.config.js I can access the build ID pretty easily:
withPWA({
webpack(config, { buildId }) {
[...]
config.plugins.push(
new CopyWebpackPlugin({
patterns: [
{
context: path.join(__dirname, 'public/static/locales'),
from: '**/*',
to: path.join(__dirname, `public/static/cache/${buildId}/locales`)
}
]
})
);
// not working:-(
process.env.CONFIG_BUILD_ID = buildId;
return config;
},
publicRuntimeConfig: {
buildId: process.env.CONFIG_BUILD_ID
}
});
However setting it to the environment variable process.env.CONFIG_BUILD_ID is not working, so publicRuntimeConfig.buildId will still be undefined.
Is there any way to access the build ID outside the next config?
Instead of
// not working:-(
process.env.CONFIG_BUILD_ID = buildId;
You should use Webpack DefinePlugin (https://webpack.js.org/plugins/define-plugin/). No extra imports or installs are needed: this plugin is already a part of the next.js package. Just replace those lines with:
config.plugins.push(
new webpack.DefinePlugin({
'process.env.CONFIG_BUILD_ID': JSON.stringify(buildId)
})
);
Full next.js.config may look like this:
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.plugins.push(
new webpack.DefinePlugin({
'process.env.CONFIG_BUILD_ID': JSON.stringify(buildId)
})
);
return config;
}
}
module.exports = nextConfig;

react native web, __DEV__ not defined

If you want to share code between RN and RN-web, __DEV__ should also be provided in the both platform.
However I can't add DEV using const __DEV__ = process.env.NODE_ENV !== 'production'; new webpack.DefinePlugin({__DEV__})
I can set window.__DEV__ fine, but RN code uses __DEV__
I've also tried adding module:metro-react-native-babel-preset
I've seen React Native - __DEV__ is not defined
/* global __DEV__ */ works, but hope there's a way to fix it without modifying all source which uses __DEV__
in your webpack.config.js, add this:
plugins: [
// `process.env.NODE_ENV === 'production'` must be `true` for production
// builds to eliminate development checks and reduce build size. You may
// wish to include additional optimizations.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
__DEV__: process.env.NODE_ENV !== 'production' || true,
}),
],
see https://medium.com/#alexander.forselius/experiment-combining-native-web-ios-android-and-macos-development-in-rectnative-part-1-ecd5887e9cfc
I solved it by making it depend on the webpack mode input.
In webpack.config.js:
const config = {
...
plugins: [],
...
}
module.exports = (env, argv) => {
config.plugins.push(new webpack.DefinePlugin({
__DEV__: JSON.stringify(argv.mode !== 'production'),
}));
return config;
};

React Native 0.60.3 babel-plugin-transform-remove-console not working

I am trying to remove console.log outputs from my react-native application's output, but when I run
ENVFILE=.env.production react-native run-android --variant=release
and
adb logcat
I still see my app's data being logged to the console.
I used the following documentation: https://facebook.github.io/react-native/docs/performance.html#using-consolelog-statements.
Here is my .babelrc file:
{
"presets": ["react-native"],
"env": {
"production": {
"plugins": ["transform-remove-console"]
}
}
}
What am I missing ?
Im on react-native 0.60.3
and using "babel-plugin-transform-remove-console": "^6.9.4",
I have "#babel/core": "^7.5.5" and "react-native": "^0.60.5"
The approach descibed in React Native Documentation was not working for me.After many try and error and exploring issues on GitHub I got it working :
In babel.config.js add this -
module.exports = api => {
const babelEnv = api.env();
const plugins = [];
//change to 'production' to check if this is working in 'development' mode
if (babelEnv !== 'development') {
plugins.push(['transform-remove-console', {exclude: ['error', 'warn']}]);
}
return {
presets: ['module:metro-react-native-babel-preset'],
plugins,
};
};
To see changes run using npm start -- --reset-cache
More Info at
https://github.com/babel/minify/issues/934
https://github.com/babel/minify/issues/950#issuecomment-539590159
Using babel.config.js instead of .babelrc, it seems that process.env.BABEL_ENV is used to determine whether to include configs listed under env.production. However, process.env.BABEL_ENV is set to undefined during build.
To get around this, I'm returning a different object depending on if process.env.BABEL_ENV OR process.env.NODE_ENV indicate production build.
YMMV.
module.exports = function(api) {
api.cache(true); // necessary
if (process.env.NODE_ENV === 'production' || process.env.BABEL_ENV === 'production') {
return {
"presets": ["module:metro-react-native-babel-preset"],
"plugins": ["react-native-paper/babel", "transform-remove-console"]
}
} else {
return {
"presets": ["module:metro-react-native-babel-preset"],
}
}
}
install babel-plugin-transform-remove-console
yarn add babel-plugin-transform-remove-console -D
then add follow code in babel.config.js like this
module.exports = function (api) {
const babelEnv = api.env();
api.cache(true);
const plugins = [
[];
if (babelEnv === 'production') {
plugins.push(['transform-remove-console', {exclude: ['error', 'warn']}]);
}
return {
presets: ['babel-preset-expo'],
plugins,
};
};
then run this command
yarn start --reset-cache
NOTE:
this will remove console.log in the production build. if you wanna a test in development you can pass development instead of production

'window is not defined' error when using style-loader with webpack

Building a server side react app and while using Webpack I am having issues with Style-Loader.
I am using version "^0.23.1" and when running a script to bundle and build there is an issue from Style-Loader.
The issue is window is not defined
webpack:///./node_modules/style-loader/lib/addStyles.js?:23
return window && document && document.all && !window.atob;
Has anyone run into this issue? After looking through Stack and the Github issues for style-loader I am not finding any solution.
Here is my webpack file:
const path = require('path');
const webpack = require('webpack');
module.exports = {
// webpack to use node
target: 'node',
entry: './src/index.js',
output: {
filename: 'client-build.js',
path: path.resolve(__dirname, 'build/public'),
publicPath: '/build/public'
},
module: {
rules: [
{
test: /\.js$|\.jsx$/,
loader: 'babel-loader',
exclude: '/node_modules/',
options: {
presets: [
'#babel/preset-react'
]
}
},
{
test: /\.(s*)css$/,
loader: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.jpeg$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$|\.wav$|\.mp3$|\.jpg$|\.pdf$/,
loader: 'file-loader',
query: {
name: 'assets/img/[name].[ext]'
},
},
]
},
plugins: [
new webpack.ProvidePlugin({
"React": "react",
}),
],
}
If there is anything else you need to see I can post it.
style-loader tries to inject styles into the head of the website (window / document), which will be non-existent on your server on render / execution.
You need to remove this loader from your server-config and replace it with something else (e.g. ExtractTextPlugin or MiniCSSExtractplugin, depending on your webpack version)
I think your problem is, that there is no window object when running js code on a node server. Which also makes sense, as your server has no window where your code is rendered. You can use the global object for global references instead, see this related post here: Does node.js have equivalent to window object in browser
If I got it correctly I think you are trying to use style-loader for bundling server side code.If it is the case try doing this instead of doing this:
loader: ['style-loader', 'css-loader', 'sass-loader']
Try this:
loader: ['css-loader/locals', 'sass-loader']
Style loader is not supposed to be used on the server side code. So we provide kind of a null-loader instead of css-loader and remove style loader. This should do the trick I guess.
I had a this problem where I needed some themes and styles from a component-library which in turn used webpack and style-loader.
My project was pure script and is supposed to generate some files and therefore had no browser. It would not compile at all since style-loader(and some other libs) tried to inject styles in the tag.
I ended up mocking window and document so that the imported project could compile.
NOTE that this worked in my case where I only needed a minor part of my component-library, if you use this in a more complicated project there will probably be some weird bugs. But it might help someone figure out a similar problem
Run this before you do the actual import
Since it is the actual import that causes the problem you need to do the hack before importing.
import * as Hack from './hack/StyleLoaderHack';
Hack.runHack();
...
import {X} from 'your library'
StyleLoaderHack.js
class HackStyle {
position;
constructor() {
this.position = [];
}
}
class HackElement {
className;
childNodes;
style;
constructor(tag) {
this.className = tag;
this.attributes = [];
this.childNodes = [];
this.style = new HackStyle();
}
appendChild = (child) => {
let append;
if (!(child instanceof HackElement)) {
append = new HackElement(child);
} else {
append = child;
}
this.childNodes.push(append);
return append;
};
insertBefore = (newChild, refChild) => {
let insert;
if (!(newChild instanceof HackElement)) {
insert = new HackElement(newChild);
} else {
insert = child;
}
this.childNodes.push(insert);
};
setAttribute = (qualifiedName, value) => {
// sketchy but works
this.attributes.push(qualifiedName);
this.attributes.push(value);
};
}
class HackDocument {
head;
constructor() {
this.head = new HackElement("head");
}
createElement = (tagName) => {
const element = new HackElement(tagName);
return element;
};
querySelector = (target) => {
const node = new HackElement(target);
return node;
};
querySelectorAll = (target) => {
if (target === "[data-emotion-css]") {
return [];
}
const node = new HackElement(target);
return [node];
};
createTextNode = (data) => {
return new HackElement(data);
};
}
/**
* Adds some function to global which is needed to load style-loader, emotion, create-emotion and react-table-hoc-fixed-columns.
*/
export const runHack = () => {
global.window = {};
const hackDocument = new HackDocument();
global.document = hackDocument;
};

Resources