Shared components with ejected create-react-app projects - reactjs

I have several projects that were created with create-react-app and have been ejected. Now, I have some components that are duplicated in each of the projects. Instead, I would like to have one shared component in a directory above the project directories.
The directory structure would be something like this:
- shared_components
- MySharedComponent.js
- project1
- project2
- project3
I updated the webpack.config.js files in my projects to allow importing files outside the src directory by adding my shared_components directory to the ModuleScopePlugin:
{
resolve: {
plugins: [
new ModuleScopePlugin([paths.appSrc, paths.mySharedComponents], [paths.appPackageJson]),
],
}
}
This successfully allows the files to be imported, but my shared_components directory doesn't seem to get compiled by the babel-loader.
I am getting the following error:
SyntaxError: /path/to/shared_components/MySharedComponent.js: Unexpected token <
This error occurs at the start of the JSX in my component, which is presumably caused by it never getting compiled to plain Javascript.
I tried updating the babel-loader config to include my shared directory, but it is not working:
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: [paths.appSrc, paths.mySharedComponents],
loader: require.resolve("babel-loader"),
// ...the rest of the config is just the defaults
}
How can I get my JSX component to successfully compile?

Related

Storybook webpack config not working - trying to run Storybook out of separate local project than components

I have a mature CRA-based React app running with Webpack 5. I would like to have a separate project (in git, etc) where Storybook lives and points to the components in the app. (The app has tons of devs in and out of it, and dropping a bunch of Storybook packages in there, as well as introducing legacy-peer-dependencies thanks to webpack 5, would be quite frowned upon).
I also want devs to have a good experience being able to use Storybook to write components, so I want Storybook to see the current code of the project components, not some exported package. And same as above, there are many devs and a lot of inertia, so moving components to a separate standalone library is not an option.
My ideal for local development:
components and stories: /MyProject-App/src/Components/...
storybook app. : /MyProject-Storybook/stories/...
(Production I'm not worried about yet)
Installing Storybook inside the app works fine (as long as you run with --legacy-peer-deps). I am using the npx storybook init script and it works fine. But if I try to run Storybook out of a separate directory and target the app directory's Components, it breaks. If I run Storybook out of the app, and point it to stories/components outside that repo (which I copied and pasted just as a debugging measure), it breaks. Going up and out of the current project root breaks.
To do this, I am trying to point stories in /MyProject-Storybook/.storybook/main.js to ../../MyProject-App/src/Components.... When I do this and npm run storybook, I get the error output:
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/#storybook/source-loader/dist/cjs/index.js
**You may need an additional loader to handle the result of these loaders.**
The error is always on some basic ES6 syntax, arrow functions etc. If I run the same Storybook install out of MyProject-App (same version numbers / same main.js just pointed at the local path instead of the ../other path) it works.
In addition to this, I tried it the other way - running storybook out of the App folder (where I know it runs), and only changing the main.js stories directory to an outside-that-repo folder where I copied my Components and stories into. It breaks in the same way - I get the same You may need an additional loader to handle the result of these loaders. message, with it pointing to any example of ES6 syntax as an 'error'.
I found this similar question - Storybook can't process TS files outside of the project
recommending to look into Storybook's webpack loaders - https://storybook.js.org/docs/react/builders/webpack
So I updated my .storybook/main.js to be the following:
module.exports = {
stories: [
'../../MyProject-Storybook/src/**/*.stories.mdx',
'../../MyProject-Storybook/src/**/*.stories.#(js|jsx|ts|tsx)'
],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
'#storybook/preset-create-react-app'
],
framework: '#storybook/react',
core: {
builder: '#storybook/builder-webpack5'
},
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.(js|jsx)$/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
reportFiles: ['../**/src/**/*.{js,jsx}', '../../MyProject-Storybook/**.stories.{js,jsx}']
}
}
]
});
config.resolve.extensions.push('.js', 'jsx');
return config;
}
};
but to no avail - output from npm run storybook remains unchanged, an excerpt:
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/#storybook/source-loader/dist/cjs/index.js
You may need an additional loader to handle the result of these loaders.
| backgroundColor: { control: 'color' },
| },
> } as ComponentMeta<typeof Button>;
|

How do I share components with external Sass stylesheets in ReactJS

I am trying to build a monorepo for my React projects as most of the code is shared between a few of my projects. I am using Yarn workspaces and Lerna for this.
I have managed to get a basic example working where the React component is shared between two projects. In this working example, however, the stylesheet is a plain CSS stylesheet and is correctly imported.
I am using Babel to transpile the React and ES6 code.
lerna exec --scope shared -- babel src -d dist --copy-files
where shared is my package containing shared components. Above command puts the transpiled JS and CSS files in the dist folder.
However, I have .scss files in my actual code base. Hence trying to replace external CSS file with external SCSS file in the example project. However, it doesn't work. The stylesheet isn't applied.
I think I understand why it must not be working. In CRA project whenever we use .scss file I think Webpack preprocesses these into .css files. In this is not happening hence the issue. Correct me if I am wrong.
I tried using Webpack instead of Babel. However, the issue that I faced was Webpack bundled all files into a single file which is something I don't want. I want that the individual component file should be transpiled and kept in the same folder structure under dist. Please see the folder structure below. shared is the package with shared components and myapp package uses the shared components.
workspace
--packages
--shared
--dist
--components
--button
--Button.js
--Button.scss
--header
--Header.js
--Header.scss
--src
--components
--button
--Button.js
--Button.scss
--header
--Header.js
--Header.scss
---myapp
My webpack.config.js
// Webpack uses this to work with directories
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
// Path and filename of the result bundle.
// Webpack will bundle all JavaScript into this file
output: {
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'commonjs2'
//filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
},
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{ test: /\.(jpg|png|gif|svg|tiff)$/, use: 'file-loader' },
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: 'file-loader' }
]
}
};
I am stuck at this point as I am not sure how I can import SCSS file in my React component which can be shared.
I'm not sure if there is a way to tell Webpack and Babel to transpile the React files and just put them in the dist folder without bundling them into a single file and also to preprocess the .scss files and use them in the transpiled files.

Syntax Error In IE 11 for this node_moduels

I am getting a syntax error in IE when this component of react is loaded in the webpage. Has anybody got the same problem? This is an inherited package, and a syntax error from node_modules makes no sense?
"use strict";
/* WEBPACK VAR INJECTION */(function(module) {
const colorConvert = __webpack_require__(/*! color-convert */ "./node_modules/color-convert/index.js");
const wrapAnsi16 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${code + offset}m`;
};
const wrapAnsi256 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${38 + offset};5;${code}m`;
};
If you are using newer versions of Node/NPM, check your package.json file -> "browserslist" section.
This is the default "browserslist" created for you if you do not have one defined:
In this case, if you run "npm start" on your LOCAL Environment, Babel will not create Polyfills for IE11 because its not included as a target browser in "development". To get this working, I deleted my node_modules directory completely, ran 'npm install', updated package.json with:
and ran 'npm start.
The reason why this fails is that babel or your other favorite transpiler might ignore node_modules (if that's how its configured), so you need to include it manually because IE does not support arrow function syntax.
First, if you search for wrapAnsi16 or wrapAnsi256 function names online it'll point you to common npm packages, such as: ansi-styles, chalk or color-convert, debug, strip-ansi, etc.
If you are using Webpack you can add the following to your rules:
module: {
rules: [{
exclude: /node_modules\/(?!(color-convert|ansi-styles|strip-ansi|ansi-regex|debug|react-dev-utils|chalk)\/).*/
}]
}
or, easier to read:
module: {
rules: [{
include: [
path.resolve(__dirname, 'node_modules/ansi-styles'),
path.resolve(__dirname, 'node_modules/strip-ansi'),
... other's here...
path.resolve(__dirname, 'src'),
]
}]
}
Hope this helps somebody in the future ;)
TLDR; you don't need this library, just run
npm run build
And it will be excluded from your build.
I have same problem with create-react-app, and I solve it (no). From my discovery, this library should not appear in browser, because it was designed for nodejs environment. Also I found, this library come to me as dependency of jest, and jest is dependency for tests and it come as dependency for react.
So, I run
npm run build
server -s build
And try my application in IE. And it work. So, when you run
npm start
It make file including dev dependencies and other garbage that should not appear in production and in browser at all. When you run
npm run build
It make file only with required project libraries.
I had similar issue #punkbit solution and installing 'react-app-polyfill'
and importing it at the top of the index.js file solved it
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
If it still does not work delete node-modules and reinstall also clear cache in IE.
All the best :)
This problem occurs because your compiled code contains (modern) ES6 syntax whilst IE11 only supports ES5.
A way to fix this is to instruct webpack to specifically compile the mentioned packages into ES5;
module: {
rules: [{
test: /\.(tsx?|js)$/,
include: [
// These dependencies have es6 syntax which ie11 doesn't like.
// Whenever you see a "SyntaxError" that crashes IE11 because of a new lib, add it here.
path.join(__dirname, 'node_modules/react-intl'),
path.join(__dirname, 'node_modules/pkce-challenge'),
path.join(__dirname, 'node_modules/fuse.js')
],
use: [{
loader: 'ts-loader', // Or whatever loader you're using
}]
}]
}
for me this was: fuse.js, pkce-challenge and react-intl.

Multiple copies of React in my Application

I am using react-treelist component and inside that i am using office-ui-fabric callout(its like a tooltip) component to have a tooltip on elements in tree structure when i am running this program it runs correctly but when i am bundling and using the bundle file in my project as a module it gives error:-
Exception in Layer.componentDidUpdate(): Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded
I have tried many solutions from diff forum but none of them worked.I am sure problem is of multiple copies of react.
Details of what i did
I cloned react-treelist from github then i installed office-ui-fabric module then i changed some code to make callout component work with react-treelist, i did npm start it worked fine the i did npm run dist and copied the bundle file to my project directory inside a folder named react-treelist and then imported that file as module in my code and ran the code it gave me the above error.
Can anybody suggest me how to accomplish the above task without having multiple copies of react in my application
If you use webpack to build your application, you can use the resolve.alias configuration option to make sure that all modules refer to the same react library:
resolve: {
alias: {
'react': fs.realpathSync('node_modules/react'),
'react-dom': fs.realpathSync('node_modules/react-dom')
}
}
If you use web pack then you can fix it by adding the following to Webpack config
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}

Multiple webpack alias configurations can't resolve modules

I am working on an Angular 2 application written in Typescript, that is using webpack in conjunction with ts-loader to bundle everything together.
I am relying heavily on webpack's resolve.alias to cater for different build outputs and I have come across an issue.
When running a specific build, ts-loader is throwing an error saying it can not find a module that is used in the current build. This, I would assume, is due to the alias pointing to a different file.
eg:
file: myApp.ts
import {Logger} from 'logger';
export class myApp {}
I have two alias JSON files, one is setup to point 'logger' at remoteSystemLogger.ts, and another which points at consoleLogger.ts
Build A will use remoteSystemLogger,
Build B will use consoleLogger
Now each logger class will import their relative dependencies. For instance:
file: remoteSystemLogger.ts
import {HTTP} from 'http';
export class Logger {}
The problem is, that when I run build B, I am getting an error saying:
ERROR in remoteSystemLogger.ts
error TS2307: Cannot find module 'http'.
http as well as remoteSystemLogger is currently not specified in the alias JSON file for Build B, as Build B should have no dependency on it.
The alias file that get's used for the webpack build is determined at build time via a param.
Here is an example of the resolve used in webpack config
let moduleAliasingConfig = `./alias/${buildType}.json`
// ....
resolve: {
root: [
path.resolve('.'),
path.resolve('node_modules')
],
alias: moduleAliasingConfig,
extensions: ['', '.ts', '.js']
},
And here is the ts-loader config:
loaders: [
{test: /\.ts$/, loaders: ['ts'], exclude: [/\.(spec|e2e)\.ts$/]}
]
I am not sure if maybe I have miss-configured something, or this is an issue with either the loader, webpack's resolver, or just my understanding of how the aliasing works.
As my understanding is, that webpack will traverse through my import/dependency tree, based on the alias file and my entry point.
Additional env info:
package.json setup:
"ts-loader": "^1.2.1",
"webpack": "^1.13.0"

Resources