Running Babel across a monorepo of packages/components - reactjs

I'm trying to build a React component library, but each component will have its own unique dependencies. To keep it tidy, I've started a monorepo using Yarn's Workspaces. It currently looks like this:
components
component1
src
index.js
dist ???
package.json
component2
src
index.js
dist ???
package.json
node_modules
package.json
.babelrc
etc.
I'd like to be able to run a Babel command at the root level that compiles each src/index.js to its relative dist/index.js. Is this possible? Or can anyone recommend a tool that can iterate this?

Figured it out. Install Lerna at root-level (with Workspace flag, to allow it to install).
yarn add --dev lerna -W
Initialise lerna.
node_modules/lerna/bin/lerna.js init
Update lerna.json to point to the "components" directory.
{
"lerna": "2.5.1",
"packages": ["components/*"],
"version": "0.0.0"
}
Add script to root-level package.json
"scripts": {
...
"build-components": "NODE_ENV=production lerna exec --parallel -- babel src -d dist",
...
},

Related

Module parse failed: unexpected token, you may need an additional loader to handle the result of these loaders

I am trying to create a npm package out of create-react-app typescript template. so far, the build is being generated but while testing it locally via npm install github_username/repo_name#branch_name it installs the package in other testing project, but I am getting this error while trying to run it.
These are the steps
Step 1 created a new react project using npx create-react-app project_name --template typescript
Step 2 Isolated components that I wanted to publish as npm package by creating lib/components inside src and lib/index.ts for exporting them.
Step 3 Installed Babel and build the dist in the root with some babel configuration.
{ "presets": [ [ "#babel/env", { "targets": { "edge": "17", "firefox": "60", "chrome": "67", "safari": "11.1" }, "useBuiltIns": "usage", "corejs": "3.6.5" } ], "#babel/preset-react" ] }
Step 4 In package.json, under scripts, replace the build script with the following:
"build": "rm -rf dist && NODE_ENV=production babel src/lib --out-dir dist --copy-files"
Step 6 npm run build
Step 7 Pushed to GitHub and install from github repo into diffrent react project and then the error came.
I am not really sure what exactly causing this error, but upon checking it seems like babel or webpack error, I tried changing some values inside tsconfig.json and webpack.config.ts (in the package repo) but it didn't solve it, also I am not very familiar with webpack.

How to create a local react library project with common components, and import that project locally

I am trying to setup a commonreact react project. I ran create-react-app, then I have created the src folder, under which I have a subfolder container. In that I have the file DefaultEnums.js
import React from 'react'
const IS_RECORD_ACTIVE = {
UNKNOWN:"UNKNOWN",
UNSPECIFIED:"UNSPECIFIED",
Active:"Active",
Inactive:"Inactive",
Draft:"Draft",
Publish:"Publish",
Unpublish:"Unpublish"
}
export default IS_RECORD_ACTIVE ;
Now I have setup another react project my-project_A and my-project_B. I want to use IS_RECORD_ACTIVE in both the two projects. How can I do it ?
I need to some how import commonreact in my other projects and then use the variable.
I am learning React, hence the silly question.
One solution is to create a module then import it in your projects by linking the module with every project.
A] Create the module
create a directory: my_module
go inside the created directory: cd my_module
covert this directory to a node module: npm init
if you don't have yarn installed, install it:
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update
sudo apt install yarn
add dependencies:
yarn add #babel/cli #babel/core
yarn add #babel/preset-env #babel/preset-react
touch .babelrc
add presets to the .babelrc file:
{
"presets": ["#babel/preset-react", "#babel/preset-env"]
}
make a source directory:
mkdir src
cd src
touch index.js
inside src/index.js add any code you want...
import React from 'react';
const DummyComponent = () => (
<div>This is my module </div>
)
export default DummyComponent;
make first build:
cd ..
./node_modules/.bin/babel src --out-file index.js
add the build command to package.json, so you don’t have to type it again and again:
{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "./node_modules/.bin/babel src --out-file index.js"
},
}
Note: whenever you want to transpile your component you can simply run: yarn build
add react & react-dom as peerDependencies. So, inside the package.json, before "devDependencies" add:
"peerDependencies": {
"react": "^16.6.1",
"react-dom": "^16.6.3" },
now install react & react-dom: yarn add react react-dom
get the path of your module (do: pwd). This command will return the module path, something like '/home/user_name/..../my_module'
B] Create your ReactJS application that you want to use the module:
do cd ..
check out if you have nodejs installed (you need: Node ^10.12.0 || >=12.0.0 or higher): npm current node -v
If you have problems with node, do: sudo mv /usr/local/bin/node /usr/local/bin/node.save
Create a ReactJS application: yarn create my-project_A
go into the new created project: cd my-project_A
add your module (the path you got from step 13): yarn add my_module_path
do: yarn start
import the module inside the App.js:
import MyModule from 'my_module'
function App() {
return (
<div className="App">
<MyModule />
</div>
);
}
export default App;
There are two ways that you can go:
Manual setup
Using create-react-library
I am sharing with you the reference links to both this approaches.
Reference links:
For manual setup
create-react-library
I hope this helps.
Looks like a wonderful project that you are working on!!

Craco build fails, taking aliased folder as external package

I'm using craco and craco-alias to implement aliases for imports in my Create React App project.
Followed instructions in https://github.com/gsoft-inc/craco/blob/master/packages/craco/README.md#installation and https://github.com/risenforces/craco-alias#readme
I configured package.json to use craco instead of react-scripts for starting dev server, tests and production build
...
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"lint:css": "stylelint './src/**/*.css'",
"lint:js": "eslint 'src/**/*.js'",
"test:w": "craco test --watch",
"postinstall": "patch-package"
},
...
Then I created jsconfig.json file w aliases paths
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"#components": ["components/*", "components"],
"#constants": ["constants/*", "constants"],
"#assets": ["assets/*", "assets"],
"#store": ["store/*", "store"],
"#utils": ["utils/*", "utils"]
},
"include": ["src"],
"exclude": ["node_modules", "build", "coverage"]
}
And craco.config.js file, which uses craco-alias plugin
/* craco.config.js */
const CracoAlias = require('craco-alias');
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
baseUrl: './src',
source: 'jsconfig',
}
}
]
}
Now I'm using aliases for imports in my app like this
// root index.js file
...
import Layout from '#components/Layout';
import store from '#store'; // this line causes error on CI build
function App() {
return (
<Layout>
/* inner components */
</Layout>
);
}
Everything works fine (aliased imports works on dev-server, in jest tests and even if I serve locally built project) until I push it to github repo. That repo has configured github actions to build and test project on remote server and it fails with error on build step, after installing all packages.
Run yarn build
yarn run v1.22.4
$ craco build
Creating an optimized production build...
Browserslist: caniuse-lite is outdated. Please run next command `npm update`
Failed to compile.
./src/index.js
Cannot find module: '#store'. Make sure this package is installed.
You can install this package by running: npm install #store.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
##[error]Process completed with exit code 1.
Could somebody help me understand what wrong with my code? Why craco or webpack expect '#store' to be external package instead of aliased import of internal module?
In my case problem wasn't in craco or webpack, but in my previous actions and OS filesystem differences. I'm using Windows 10 and WSL in VS Code terminal. So before I use '#' symbol for aliases I tried to use CamelCase for my folders and renamed it via windows explorer (because for me it was simpler to close VSCode and rename files via explorer than to open new bash terminal in new VSCode window after closing opened files).
Then I prefer to use '#' symbol and rename folders back to lowercase. I configured aliases and pushed changes to remote github repo, where CI actions were run. When CI was running actions it can't find 'store' folder (because previously I renamed it to 'Store' and it was last saved path to folder in git), so it tried to find external package named 'store'.
To fix this I change git config to stop ignoring namecasing for my folder by running command git config core.ignorecase false. Git history was updated, I push it to remote repo and CI actions succeeded.

Babel not transpile files from parent dir

How can I tell babel to transpile files that are not in current (root) directory?
Here is my project structure:
|-project
|build
|-node_modules
-.babel.rc
-package.json
|src
|test
My source files are in "src", my test files are in "test".
I want to run mocha test from my package json script. I use babel to transpile my src files (ES6, React) on the fly.
Here is my package.json:
"scripts": {
"test": "mocha --require #babel/register '../test/**/*Test.js'"
}
and .babelrc:
{
"presets": [
"#babel/preset-env",
"#babel/preset-react"
]
}
But when I run yarn test, I get error message like this:
/src/App.spec.js:1
(function (exports, require, module, __filename, __dirname) { import React from 'react';
^^^^^^
SyntaxError: Unexpected token import
I'v tried milion config combination, but nothing works, I don't want to have package.json and babel config files in the project root (that works) and I couldn't figure it out how to tell babel what to transpile, without changing project structure.
From the error you posted, it seems your babel configuration cannot process jsx syntax. You can resolve this by installing #babel/plugin-transform-react-jsx plugin.
And configuring it like so:
.babelrc
{
...
"plugins": ["#babel/plugin-transform-react-jsx"]
}
I finally came to this solution:
package.json:
"test": "NODE_PATH=$PWD/node_modules:$PWD/../src/ mocha --require babelRegister.js ../test/**/*.spec.js"
babelRegister.js:
require('#babel/register')({
extends: './.babelrc',
ignore: [/node_modules/],
});
Both "extends" and "ignore" must be set, otherwise it's not working. Looks hackish but I didn't find better solution.

How to convert create-react-app to Preact?

As per Preact documentation, to convert a React app to Preact you have to alias webpack:
{
"resolve": {
"alias": {
"react": "preact-compat",
"react-dom": "preact-compat"
}
}
}
How can you do this with create-react-app since that hides webpack under react-scripts dependency?
Thank you!
I think the most elegant solution is to use customize-cra. This way you can avoid ejecting or maintaining a separate fork of create-react-app.
First, you need to install customize-cra:
yarn add customize-cra react-app-rewired --D
Then, go to package.json, change your scripts to the following (this step is crucial but is not explicitly mentioned in customize-cra's docs):
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
Go to the root of your project, create a file called config-overrides.js with the following content (assuming you're using Preact X):
const { override, addWebpackAlias } = require('customize-cra');
module.exports = override(
addWebpackAlias({
'react': 'preact/compat',
'react-dom': 'preact/compat'
})
);
Run yarn start... And Voila!
There's Preact CLI which allows you to create preact apps without any module bundlers. It's the recommended tool to create starters for Preact apps.
npx preact-cli create default my-project
# Go into the generated project folder
cd my-project
# Start a development server
npm run dev
Watch out for templates which are using Preact 8.x. The newest version (as of 7/25/21) is Preact X (Preact version 10.x). The default template uses Preact X.
If you want to use create-react-app to make a Preact app, you can use this workaround (documented here):
npx create-react-app my-app --scripts-version #just-boris/preact-scripts
cd my-app
# The dependencies used by `create-react-app` are still pointing to
# react, so under root application folder it's required to run:
npm uninstall react react-dom
npm install preact
# `preact-compact` is bundled with `preact` under `preact/compact` in
# Preact X, but if you are using an older version run this:
# npm install preact-compact
This can also be done with yarn.
Preact official docs
Section on how to upgrade from Preact 8.x to Preact X
In my experience, the app created with the 2nd approach started seamlessly. However, I didn't try importing any complex/advanced React components.
I had issues porting such components into a Preact app created with preact-cli. I'll try again and provide more details if needed.
Alternatively, you can get it working with craco:
// craco.config.js
module.exports = {
webpack: {
alias: {
"react": "preact/compat",
"react-dom": "preact/compat"
}
}
}
Note: Do not uninstall react, #types/react, or #types/react-dom after adding preact!
react is still required by react-scripts to run craco start and friends.
#types/* are still required by your IDE for type suggestions.
Note: Bundle analyzers may still report that you're using React!
Make sure to double-check your output directory for real build sizes.

Resources