No event handlers fire with React production build using Rollup - reactjs

In our project we're using Rollup to build/bundle our code with code-splitting via React lazy on our routes. With a development build, everything works fine; our button and dropdown event handlers fire. In a production build, none of the handlers fire. It gets more interesting. If we don't do code-splitting at the route level and just have a single bundle file with everything, both development and production builds work perfectly. I'm wondering if I'm missing an option for any of my Rollup plugins that is causing this behavior?
envVars.exclude = 'node_modules/**';
envVars.preventAssignment = true;
const minifier = isDebugBuild ? null : terser();
rollup({
preserveEntrySignatures: false,
input: paths.scripts.src,
plugins: [
replace(envVars), // Replace all env vars.
nodeResolve({ // Resolve any imported node modules.
browser: true // Ensure all node modules are ready for browser use.
}),
json(), // Convert imported json files as modules.
commonjs({
include: 'node_modules/**'
}),
babel({ // Have Babel transpile our scripts to es6.
babelHelpers: 'runtime', // Include Babel runtime helpers in our scripts.
exclude: 'node_modules/**' // Don't transpile any modules imported from node.,
}),
minifier
]
})
.then((bundle) => {
const entryFileOutputName = isDebugBuild ? paths.scripts.entryFile : paths.scripts.entryFileMinifiedName;
const chunkFileOutputName = isDebugBuild ? paths.scripts.chunkFile : paths.scripts.chunkFileMinifiedName;
return bundle.write({
dir: paths.scripts.build, // The final output directory.
entryFileNames: entryFileOutputName, // The main entry script.
chunkFileNames: chunkFileOutputName, // The chunk scripts that will be lazy loaded.
format: 'es', // The final format of the bundles scripts. Here we want ES6+ JS.
sourcemap: isDebugBuild // Generate source maps or not.
});
});

Related

#react-three/fiber node module not working in Expo app

I have an expo app .. all the mode modules are js ones. Now I am trying to add #react-three/fiber which I think is written in typescript. So, i feel the module is not working as expo is not compiling the ts or tsx files as it does with the js files. Can someone tell me how to make expo to build ts files also alongside the existing js files and node modules. Is expo capable of handling both js and ts in same project ? Below is the exception i am getting on opening the App
* /<projectpath>/node_modules/#react-three/fiber/dist/native.js(.native|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx|.android.js|.native.js|.js|.android.jsx|.native.jsx|.jsx|.android.json|.native.json|.json)
* /<projectpath>/node_modules/#react-three/fiber/dist/native.js/index(.native|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx|.android.js|.native.js|.js|.android.jsx|.native.jsx|.jsx|.android.json|.native.json|.json)
Android Bundling failed 1083ms
While trying to resolve module `#react-three/fiber` from file `/<projectpath>/src/screens/spinner/spinner-3d-60deg.js`, the package `/<projectpath>/node_modules/#react-three/fiber/package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved (`/mnt/57b4f320-a355-468b-a1f5-2d4d156e25e8/projects/external/PickABoo/node_modules/#react-three/fiber/dist/native.js`. Indeed, none of these files exist:
* /<projectpath>/node_modules/#react-three/fiber/dist/native.js(.native|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx|.android.js|.native.js|.js|.android.jsx|.native.jsx|.jsx|.android.json|.native.json|.json)
* /<projectpath>/node_modules/#react-three/fiber/dist/native.js/index(.native|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx|.android.js|.native.js|.js|.android.jsx|.native.jsx|.jsx|.android.json|.native.json|.json)
You need to configure metro to compile typescript files.
Edit metro.config.js (located in your project's root folder) and make sure you have the following sourceExts: ['jsx', 'js', 'ts', 'tsx'] within your resolver options.
See relevant documentation here: https://facebook.github.io/metro/docs/configuration/#sourceexts
If you don't already have a metro.config.js file in your root folder, you can create one and enter the code below:
metro.config.js
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
resolver: {
sourceExts: ['jsx', 'js', 'ts', 'tsx'], // this line compiles typescript
},
};

Storybook - no stories showing up in typescript project with custom webpack / babel

I am trying to set up Storybook in a project. My project is runing on react#^16, and I'm using typescript, with a custom babel and webpack setup for development and build. To set up storybook, I did
npx sb init
This installs everything needed. It puts a .storybook folder in the root folder, and a stories folder in my src folder with some prefab components and stories in tsx format (which is what I want):
The .storybook/main.js file seems fine:
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials"
]
}
And the average .stories.js file automatically installed by npx sb init also seems fine:
import React from 'react';
// also exported from '#storybook/react' if you can deal with breaking changes in 6.1
import { Story, Meta } from '#storybook/react/types-6-0';
import { Header, HeaderProps } from './Header';
export default {
title: 'Example/Header',
component: Header,
} as Meta;
const Template: Story<HeaderProps> = (args) => <Header {...args} />;
export const LoggedIn = Template.bind({});
LoggedIn.args = {
user: {},
};
export const LoggedOut = Template.bind({});
LoggedOut.args = {};
But when I run npm run storybook, the storybook landing page has no stories. Even though it had installed some default stories to start playing with. It says:
Oh no! Your Storybook is empty. Possible reasons why:
The glob specified in main.js isn't correct.
No stories are defined in your story files.
As requested, here is a link to the repo so you can dig a bit deeper into the structure, weback config, etc. Note I have not committed the npx sb init changes yet, so you won't see the files there, only my starting point just before running the sb init.
I haven't had any issues getting npx sb init to work with a standard create-react-app, but with my custom webpack build and typescript, its just empty. What's going wrong?
Edit: Additional detail
I realize that just running npx sb init, then npm run storybook throws this error:
ERROR in ./.storybook/preview.js-generated-config-entry.js
Module not found: Error: Can't resolve 'core-js/modules/es.array.filter'
Based on this thread, installing core-js#3 solves the problem and storybook runs, though with no stories.
It seems like the babel plugin transform-es2015-modules-amd doesn't fit right with storybook since sb still uses your babel configuration.
You might need to remove it then it would work:
{
"plugins": [
// "transform-es2015-modules-amd", // Remove this plugin
]
}
If you want to have a special babel configuration for storybook, place it .storybook/.babelrc so the configuration would be simple like this:
.storybook/.babelrc:
{
"presets": ["#babel/preset-env", "#babel/preset-react", "#babel/preset-typescript"]
}
NOTE: You might miss to forget install #babel/preset-typescript to help you transform your typescript code.
Maybe you have problems with the stories path, try to save only "../src/**/*.stories.js" in your config to see if its the reason
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
]
In case of dealing with arcgis-js-api in sb, you have to declare #arcgis/webpack-plugin in storybook's webpack configuration by adding to its config.
Here are a few steps you have to do:
Add webpackFinal property in .storybook/main.js with following content:
const ArcGISPlugin = require('#arcgis/webpack-plugin');
module.exports = {
// ...
webpackFinal: (config) => {
// Add your plugin
config.plugins.push(
new ArcGISPlugin(),
);
// Since this package has used some node's API so you might have to stop using it as client side
config.node = {
...config.node,
process: false,
fs: "empty"
};
return config;
}
};
One more thing to be aware of, some components are importing scss files, so you might need to support it by adding a scss addon '#storybook/preset-scss'
// Install
npm i -D #storybook/preset-scss css-loader sass-loader style-loader
// Add to your current addons
{
addons: ['#storybook/addon-links', '#storybook/addon-essentials', '#storybook/preset-scss'],
}
Like a tmhao2005 say. Storybook still uses your babel configuration. And this is the intended behavior. This thread at github also describes how the fix similar issue.
Updated your config .storybook/main.js.
If you use .babelrc:
babel: async options => ({ ...options, babelrc: false })
Or .babel.config.js:
babel: async options => ({ ...options, configFile: false })

react lazy load external amd modules

My react app has external resources outside src/ so i have ejected react-scripts and disabled ModuleScopePlugin.
Referenced the external library in resolve.alias and used across the application.
resolve.alias: {
'genlib': path.resolve(fs.realpathSync(process.cwd()), 'lib/genlib/js/src'),
'config': path.resolve(fs.realpathSync(process.cwd()), 'config/dev'),
'messages': path.resolve(fs.realpathSync(process.cwd()), 'config/messages')
}
genlib is the external library im trying to reference.
The external library is AMD using requirejs.
One of the file in the library lazy loads a class using require.
define('class1', ['require', ...], function(require, ...) {
//
require([variable], function()...)
});
The above require is throwing Cannot find module 'xxx' at runtime from webpackEmptyContext.
When require from above code is consoled then below is logged instead of require function. Confused why webpackEmptyContext is consoled out instead of webpackContext function
ƒ webpackEmptyContext(req) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
I have not changed any of the webpack.config.js except adding alias and disabling ModuleScopePlugin.
What else needs to be added or changed in config to lazy load amd modules.
webpack v4.19.1
react-dev-utils v7.0.1
I have solved by using ContextReplacementPlugin.
Added below code to webpack config plugins.
new webpack.ContextReplacementPlugin(/genlib[\\/]services/, /.*$/),
Now a map is created with all the files in the services directory and webpackContext loads the files when required.
You will see babel-loader in return object of webpack.config.js file. module -> rules array First code is to run the linter
{
test: /\.(js|mjs|jsx)$/,
enforce: 'pre',
use: [
{
options: {
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
},
loader: require.resolve('eslint-loader'),
},
],
include: [
paths.appSrc,
'paht/to/external-library/using/requirejs' <---- Add your external file path for loader to parse the AMD files
],
}
Similarly include file path to test entry of JS files
test: /\.(js|mjs|jsx|ts|tsx)$/,
Can you try this and check?

Create React App 2 - remove html attribute for testing

Is it possible to connect Create React App 2 with this plugin: https://www.npmjs.com/package/babel-plugin-jsx-remove-data-test-id without ejecting?
I've created .bablerc file, but it doesn't work.
I want to use custom attribute for bdd testing and remove this attribute on production.
Also, I don't want to create HOC to apply attribute - I have many components and wrap every component is very very difficult.
You can use react-app-rewired https://www.npmjs.com/package/react-app-rewired and override the configs through the config-override.js file:
const {
override,
addBabelPresets,
addBabelPlugins,
} = require('customize-cra');
module.exports = override(
...addBabelPresets([
'#babel/preset-env',
{
modules: false,
useBuiltIns: false,
debug: false,
},
]),
...addBabelPlugins(
'babel-plugin-styled-components',
'babel-plugin-jsx-remove-data-test-id',
),
);

React multiple output files of bundle of single Input file

I am working in React and want to publish my code . I am creating bundle using webpack , since I want the bundle to be divided in three parts , that is , my code should have divided in to three different files so that not only one file get populated too much . I went through the official docs of webpack and other online sites but still not found the solution for this .
Here is a complete configuration webpack.config.js that you can base yours on.
const webpack = require('webpack');
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const WebpackConfig = {
// multiple component entry points
entry: {
AppPart1: './src/AppPart1',
AppPart2: './src/AppPart2',
AppPart3: './src/AppPart3'
},
// generate files
output: {
path: './assets',
// creates JS files like "AppPart1.js"
filename: '[name].js'
},
module: {
preLoaders: [
// add any pre-loaders here, OPTIONAL
],
loaders: [
// add any loaders here, like for ES6+ transpiling, React JSX etc
]
},
resolve: {
extensions: ['.jsx', '.js']
},
plugins: [
// this will factor out some common code into `bundle.js`
new CommonsChunkPlugin('bundle.js'),
]
};
module.exports = WebpackConfig;
At the end of webpack build, here is what you will have in the assets folder
AppPart1.js
AppPart2.js
AppPart3.js
bundle.js
bundle.js will contain some shared code and must be included on all your pages along with the appropriate part file for the page.
If you have the three separate files, you can put multiple entry points on your webpack config:
entry: {
"bundle1":"./src/app/somefile1.jsx",
"bundle2":"./src/app/somefile2.jsx,
"bundle3":"./src/app/somefile2.jsx"
}

Resources