We can start with React project using command create-react-app. But when we use this command we don't get idea about how it's bundle and pack all types of files using Webpack.
So I tried to build react app without create-react-app command using Webpack 4 and Babel 7 and I succeed.
Now I want to do same app using parcel bundler. as I read on different blogs I got an idea that parcel is easy then web pack and it's truly zero configuration set up.
My project structure is
- src
|- components
|- styles
|- index.html
|- index.js
- package.json
This is simple project to start with parcel bundle so I've not add Redux or routing yet.
What I want to achieve is
1). As aspected React app should be run in browser using parcel bundler.
2). I want to use absolute paths when importing JS files.
3). I want to enable hot reloading.
After few minutes of research on net I find the solution and it's truly zero configuration with parcel bundler.
we just need to add 2 commands in package.json file 's script section.
project structure is
- src
|- components
|- styles
|- index.html
|- index.js
|- App.js
- package.json
- .babelrc // this file will use to setup absolute path when import files
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from './App';
import "./style/index.scss";
ReactDOM.render(<App />, root);
index.html is same file as create-react-app provide we just need div with id.
App.js
import React, { Component } from "react";
import Count from "#components/Count"; // here I used absolute path. check .bablerc file
export default class App extends Component {
render() {
return (
<>
<div>this is App component</div>
<Count />
</>
);
}
}
components/Count.js
import React, { Component } from "react";
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<>
count is: {this.state.count}
<br />
<button onClick={(prevState) => {this.setState({
count: prevState.count + 1
});
}}
>
Add count
</button>
</>
);
}
}
style/index.scss
body {
background-color: red;
color: #fff;
text-align: center;
font-size: 40px;
}
note that we don't need to manually install node-sass package to use
scss. parcel will handle for you.
package.json
{
"name": "react_parcel",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "parcel ./src/index.html",
"build": "parcel build ./src/index.html/"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"parcel-bundler": "^1.12.3",
},
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}
.bablerc
{
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"alias": {
"#components": "./src/components"
}
}
],
["react-hot-loader/babel"]
]
}
here we add alias for components folder so when we need to import any file from components folder we don't need to write relative path.
npm run dev
your server will start on localhost:1234
I solved 2 issues but still need to figure out how to use hot reloading so if you guys have any idea related hot reloading please answer it.
for production build: npm run build
Related
I made a create-react-app. Now I am trying to refactor some of the react components into a private library named "myLibrary" (initiated with create-react-library) which is in a folder named "myLibrary", sitting next to "myApp". "myLibrary" is intended to be a collection of independant, reusable react components (conventionally one file per), css, and other web assets.
package.json for "myLibrary"
{
"name": "myLibrary",
"private": true,
"main": "dist/index.js",
"source": "src/index.js",
"type": "module",
"exports": {
"./": "./src/"
},
...
package.json for "myApp"
{
"name": "myApp",
"dependencies": {
"myLibrary": "file:../myLibrary",
...
Now, in "myApp" I try to import a react component
import BaseLayout from 'myLibrary/layout/base'
but I get the following error:
ERROR in ../myLibrary/src/layout/base.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /myLibrary/src/layout/base.js: Support for the experimental syntax 'jsx' isn't currently enabled (9:7):
7 | render(){
8 | return (
> 9 | <>
| ^
10 | <Header />
11 | <main>
12 | </main>
Add #babel/preset-react (https://github.com/babel/babel/tree/main/packages/babel-preset-react) to the 'presets' section of your Babel config to enable transformation.
If you want to leave it as-is, add #babel/plugin-syntax-jsx (https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-jsx) to the 'plugins' section to enable parsing.
I added a .babelrc to "myApp" with
{
"presets": ["#babel/preset-react", "#babel/preset-env"],
"plugins": ["#babel/plugin-transform-react-jsx"]
}
and since this is a create-react-app, I tried both react-app-rewired/customize-cra as well as ejecting to use .babelrc. After confirming that .babelrc is loaded, I still get the same error. I've also tried the following and still get the same problem:
src/index.js for "myLibrary"
import BaseLayout from './layout/base.js'
export { BaseLayout }
In "myApp"
import BaseLayout from 'myLibrary'
What is going on?
check node_modules/react-scripts/config/webpack.config.js and look for
// #remove-on-eject-begin
babelrc: false,
configFile: false,
then set babelrc: true, to enable .babelrc file changes to work
note : You have to put .babelrc.json in the src folder of 'MyApp' (same folder where you have package.json
I am beginner in React and I am struggling with compiler error. Let me introduce my situation. I have two independent React applications:
App A - Big ERP
App B - "Plugin" to the App A
I supposed I will develop App B as an independent application. Then, I will install it to the App A (using npm install git#github.repo/...) once I finish development of the App B. I expected I will call components from App B within the App A source code. Everything went fine until I run the compilation. I am receiving:
SyntaxError: /frontend/node_modules/connector_frontend/src/views/Connector/FormView/index.js: Unexpected token
In my /frontend/node_modules/connector_frontend/src/views/Connector/FormView/index.js there is following code:
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
<p>Hello world</p>
)
}
export default ConnectorFormView;
Error is ocuring at the position of <p>.
I call this functional component from App A (frontend/src/views/Connector/ConnectorNewEditView/index.js) like this
import ConnectorFormView from "connector_frontend/src/views/Connector/FormView";
const ConnectorNewEditView = () => {
return (<ConnectorFormView AppValues={appValues} secureFetch={secureFetch} />)
}
export default ConnectorNewEditView;
I tried to return just a plain text from the ConnectorFormView component like this:
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
'Hello world'
)
}
export default ConnectorFormView;
and it was compiled successfully, but once I return a JSX from the ConnectorFormView component the compiler get crashed.
Can anyone explain the source of this error please?
I successfully figured out the source of this problem and also I found a solution. I expected I can reuse however React component implemented in JSX. I expected, the only requirement is to install it, resp. download it in JSX form to my project using NPM. It's FALSE.
According to my research, I can reuse React components compiled from JSX to ES only. It is achievable using Babel. Another very important requiremen, it should not by installed as React application as I installed it. It must be installed as a NPM package with clearly defined set of exported components.
I found this paper https://levelup.gitconnected.com/publish-react-components-as-an-npm-package-7a671a2fb7f and I followed it step by step and finally I achieved desired result.
I can very briefly mention steps which I performed:
Implemented my custom component (mentioned above)
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
<p>Hello world</p>
)
}
export default ConnectorFormView;
Added the component to /src/index.js file in order to export it for host App
import ConnectorFormView from './components/ConnectorFormView';
export { ConnectorFormView };
Installed Babel and all needed presets
npm install --save-dev #babel/core #babel/cli #babel/preset-env
npm install -save #babel/polyfill
configured Babel - created file /babel.config.json with following content
{
"presets": [
[
"#babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
],
"#babel/preset-react"
]
}
Added new script to the package.json to compile React components to ES:
"build": "rm -rf dist && NODE_ENV=production babel src --out-dir dist --copy-files";
Executed npm run build to compile React components to ES. Compiled components are located in new dist folder.
Adjusted package.json that looks like this now
{
"name": "my_react_components",
"version": "0.1.0",
"private": true,
"description": "Some description",
"author": "Lukas",
"main": "dist/index.js",
"module": "dist/index.js",
"files": [ "dist", "README.md" ],
"dependencies": {
.
.
},
"scripts": {
"build": "rm -rf dist && NODE_ENV=production babel src--out-dir dist --copy-files",
.
.
.
},
"eslintConfig": {
"extends": "react-app"
},
"devDependencies": {
"#babel/cli": "^7.17.10",
"#babel/core": "^7.18.5",
"#babel/preset-env": "^7.18.2"
}
}
Pushed dist folder to the git.
Installed repository to the host project using NPM
npm install https://github.com/my_custom/react_component.git
Import and use the component from installed git repo
import ConnectorFormView from 'my_react_components';
function App() {
return (
<ConnectorFormView />
);
}
export default App;
Actually that's all. I very recommend to see the attached paper at the beginning of this answer because I maybe skipped very important info for you.
I am attempting to install tailwind (Which I have done many times before with no issue). Please help me with what I am missing this time around.
tailwind.config.js
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Package.json
....
"devDependencies": {
.....
"autoprefixer": "^10.4.2",
"postcss": "^8.4.6",
"tailwindcss": "^3.0.23"
},
....
index.js
import './index.css'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
app.js
const App = () => {
return <div className='bg-blue-300'>
cool
</div>
}
And lastly (where I believe my problem is)
index.css
#tailwind base;
#tailwind components;
#tailwind utilities;
body{
background-color: red; /* I WORK FYI! */
}
(EDIT) A bit more info: This app is the 'example-app' generated after running using create-react-library. I just created a brand new react app, installed TW, and had no problems. I also installed another package into my example-app (react-icons) just to test that wasn't the issue but that works as expected.
Do you start the Tailwind CLI build process?
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
I'm trying to create custom react components based on Liferay's Clay components.
Using e.g. just a ClayButton works, but as soon as i try to use hooks (like React.useState), the browser console tells me:
Minified React error #321; visit https://reactjs.org/docs/error-decoder.html?invariant=321 for the full message
The full message tells me i could be using mismatching versions of react and react-dom. I'm not.
I also don't have 2 different versions of react, according to the test described there.
I created a minimal example module at https://github.com/ReFl3x0r/liferay-react-component-test which can be tested in a Liferay Gradle Workspace.
There's also an older thread in Liferay Forums discussing this error, but with no solution.
(https://liferay.dev/ask/questions/development/re-lr-7-3-react-portlet-invalid-hook-call)
What am i doing wrong?
EDIT:
Trying to point out the main code snippets.
First CustomButtonFail.es.js:
import React from 'react';
import ClayButton from '#clayui/button';
const CustomButton = () => {
const [name, setName] = React.useState('test');
return (
<ClayButton displayStyle='primary'>
TEST
</ClayButton>
);
}
export default CustomButton;
The package.json:
{
"dependencies": {
"#clayui/button": "^3.40.0",
"#clayui/css": "3.x",
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
"devDependencies": {
"#liferay/npm-scripts": "47.0.0",
"react-test-renderer": "^16.12.0"
},
"name": "component-test",
"scripts": {
"build": "liferay-npm-scripts build"
},
"version": "1.0.0"
}
The view.jsp including the component (shortened):
<%#taglib uri="http://liferay.com/tld/react" prefix="react" %>
<div class="react-component-failing">
<react:component
module="js/CustomButtonFail.es"
/>
</div>
I finally got it working. Reducing package.json like this:
{
"devDependencies": {
"#liferay/npm-scripts": "47.0.0"
},
"name": "component-test",
"scripts": {
"build": "liferay-npm-scripts build"
},
"version": "1.0.0"
}
and adding a ".npmbundlerrc" in modules root with content:
{
"config": {
"imports": {
"frontend-taglib-clay": {
"#clayui/button": ">=3.40.0",
"#clayui/css": ">=3.x"
},
"#liferay/frontend-js-react-web": {
"react": ">=16.12.0"
}
}
}
}
did the trick.
Working example is at https://github.com/ReFl3x0r/liferay-react-component-test/tree/working
I've got a frontend (next.js) which has tailwindcss installed (config, postcss, ...) and everything works.
I've made another package (ui) which has the following package.json
{
"name": "ui",
"version": "1.0.0",
"private": true,
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"autoprefixer": "^10.3.2",
"postcss": "^8.3.6",
"tailwindcss": "^2.2.7"
}
}
The problem is when is serve the ui locally everything works fine (the UI sees the styles of the component), but when deployed to vercel, the component has no styles in it.
The component (ui):
import React from 'react';
const Example = ({children}) => <button className='bg-blue-500 py-1 px-2'>{children}</button>
export default Example
And my next config (frontend)
const withTM = require('next-transpile-modules')(['bar'])
module.exports = withTM()
Is there a way of sharing the same tailwind.config.js ? Or anything to make it work.
Steps that I have made:
created the workspace
added frontend package (next, and then i installed tailwind with all the steps from their docs)
added the ui package (installed the peerDependencies, see above)
created the component
added the ui package as a dependency in the frontend, yarn install, and then imported the component
yarn dev, and the styles are applied locally.
deployed to vercel, the button has only the children , no styles
UPDATE:
The problem is caused by the purging process at build time.
Is there any way to specify in the tailwind config to purge also the ui package?
UPDATE2:
I've tried to add the package (i've renamed it to "#example/ui") to the purge in next.config.js
module.exports = {
purge: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./node_modules/#example/ui/src/*.{js,ts,jsx,tsx}'
],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
The code in the UI package is inside of the src, has only the index.tsx file. I mention, locally still works fine.
Solved it !
In the purge array , I needed to add the node modules from the root of the project, not of the frontend