An open API service indexing awesome lists of open source software.

https://github.com/mohammedhrima/urajs

Frontend framework built with JavaScript/TypeScript
https://github.com/mohammedhrima/urajs

framework front-end frontend javascript open-source typescript

Last synced: 9 months ago
JSON representation

Frontend framework built with JavaScript/TypeScript

Awesome Lists containing this project

README

          


Logo

**UraJS** is a lightweight single-page application (SPA) framework designed to make building interactive and dynamic web applications intuitive and efficient.

Inspired by the simplicity of **React**, the directory-based routing of **Next.js**, UraJS introduces its own take on SPA development. Its directory-based routing system automatically generates routes from the file structure, streamlining navigation setup for developers.

With built-in support for **live reloading**, **state-driven UI updates**.

## Summary
- [Get Started](#get-started)
- [Generate Route](#generate-component-or-route)
- [Example Generated JSX](#example-generated-jsx)
- [Folders Structure](#folders-structure)
- [Configuration](#configuration)
- [Navigate between routes](#navigate-between-routes)
- [Navigate with Parameters](#navigate-with-parameters)
- [Tailwind](#tailwind)
- [Conditions `//`](#conditions)
- [Loops ``](#loops)
- [Component Composition](#component-composition)
- [Deploy using Docker](#deploy-using-docker)

## Get Started
To get started with **UraJS**, follow these simple steps:
1. **Clone the repository**:
```bash
git clone https://github.com/mohammedhrima/UraJS
```
2. **Navigate to the project directory**:
```bash
cd UraJS
```
3. **Install the dependencies**:
```bash
npm install
```
4. **Start the development server**:
```bash
npm start
```
5. **Open your browser** and visit http://localhost:17000 to see the app running.
+ you should see something like this


Logo

6. **all commands**:
```bash
npm start #start server
```
```bash
npm run clear #clear outfile
```
```bash
npm run route #create route
```
```bash
npm run comp #create component
```
```bash
npm run build #to build
```
```bash
npm run config #change configuration
```

## Generate Route
To generate routes automatically, you can use the following commands:
- To generate a **basic route and its CSS/SCSS file if neede**, run:

```bash
npm run route /helloworld
```

+ This will create
`pages/helloworld/helloworld.[jsx|tsx]` mapped to the /helloworld route.
`pages/helloworld/helloworld.[css|scss]` for styling the route.
After generating the route and its styles, visit the route in the browser by navigating to the corresponding URL `http://localhost:17000/helloworld`

- To generate a **nested route and its SCSS file**, run:

```bash
npm run route /helloworld/again
```

## Example Generated JSX
+ Component:
```js
import Ura from 'ura';

function Component() {
const [render, State] = Ura.init(); // Initialize Ura and state management
const [getter, setter] = State(0); // Declare a state with an initial value of 0

return render(() => (


Hello from the Component component!


setter(getter() + 1)}>
Click me [{getter()}]


));
}

export default Component;
```
+ Route: Route tag should have `` so the can be viewed
```js
function Route() {
document.title = "Route Page";
const [render, State] = Ura.init();
const [count, setCount] = State(0);
const [darkMode, setDarkMode] = State(true);

return render(() => (



UraJS


GitHub
setDarkMode(!darkMode())}>
{darkMode() ? 'Light Mode' : 'Dark Mode'}



Welcome to UraJS


Lightweight. Reactive. Yours.


setCount(count() + 1)}>
Click me [{count()}]


Built with 💙 using UraJS





));
}
export default Route;
```
#### Explanation of the Code:
1. State:
- used to updated the view wherever the value change: `const [getter, setter] = State(initialValue); `
- componenet can hold multiple states
- essential for updating the view weh state change
2. Rendering the Component:
+ `return render(() => ( ... ))`: saves JSX component for future reconciliation.
3. Event Handling:
+ ` setter(getter() + 1)}>`: onlick state change
+ In UraJS, event names should be written in lowercase. This is the standard convention for handling events in JavaScript.
+ For example:
+ `onclick` for mouse clicks.
+ `onchange` for input changes.
+ `onkeyup` for key presses.
For a complete list of event names, check W3Schools JavaScript Events (https://www.w3schools.com/jsref/obj_events.asp)
4. `` reference to the `
` in ./src/index.html

## Folders structure:
```
UraJS/
├── out/ # Production-ready transpiled JavaScript files
│ └── (All framework and app code transpiled to vanilla JS)
│
├── scripts/ # scripts used by the framework.
│
├── src/
│ ├── assets/ # Static assets
│ │ └── (image.png, ...)
│ │
│ ├── components/ # Reusable UI components
│ │ ├── Button/ # Example component
│ │ │ ├── Button.jsx
│ │ │ └── Button.css
│ │ └── (Other components...)
│ │
│ ├── pages/ # Route-based components
│ │ ├── home/ # Example route: /home
│ │ │ ├── home.jsx # Route component
│ │ │ └── home.css # Route-specific styles
│ │ │
│ │ ├── main.js # Application entry point
│ │ ├── main.scss # Global styles/variables
│ │ └── tailwind.css # Tailwind imports (if enabled)
│ │
│ ├── services/ # Business logic/services
│ │ ├── api.jsx # API service layer
│ │ └── events.js # Event bus/service (in developement)
│ │
│ └── ura/ # Framework frontend code
│
├── tailwind.config.js # Tailwind CSS configuration
├── ura.config.js # Framework configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Project dependencies and scripts

```

## Configuration
+ The `ura.config.js` file allows you to customize various settings for your project
+ Default config:
```js
typescript: "disable"
dirRouting: "enable"
defaultRoute: "home"
tailwind: "disable"
scss: "disable"
css: "enable"
port: 17000
```
+ to change it: run
```bash
npm run config #change configuration
```
+ you will get a validation messages like this


Logo

## Navigate between routes
```bash
npm run route /home
npm run route /about
npm run comp /navbar
```
```js
// components/Navbar.jsx
import Ura from 'ura';

function Navbar() {
const [render, State] = Ura.init();

return render(() => (


  • Ura.navigate("/home")}>Home

  • Ura.navigate("/about")}>About



));
}

export default Navbar;
```
**Explanation of the navigate Hook:**

+ `Ura.navigate` is a built-in function in UraJS that programmatically changes the current route of the app. When you call this function, it will update the URL and load the corresponding component.

### Adding the Navbar to the Home Page
Once the `Navbar` component is created, you can include it in your `home` page component. For instance:

```js
// pages/home/home.jsx
import Ura from 'ura';
import Navbar from '../../components/Navbar.js';

function Home() {
const [render, State] = Ura.init();

return render(() => (



Welcome to the Home Page!




));
}

export default Home;
```

## Navigate with Parameters
```bash
npm run route /home
npm run route /user
npm run comp /navbar
```
This component uses Ura.navigate to navigate to a new page (`/user`) and passes the `name` and `email` parameters.
```js
import Ura from 'ura';

function Home() {
const [render, State] = Ura.init();

return render(() => (


Welcome to the Home Page!


Ura.navigate("/user", { name: "John Doe", email: "john.doe@example.com" })}>
Show Details



));
}

export default Home;
```
#### Component That Receives and Visualizes the Parameters
This component receives the name and email parameters from the navigation and displays them.
```js
import Ura from 'ura';

function User() {
const { name, email } = Ura.getParams();
const [render, State] = Ura.init();

return render(() => (


User Name: {name}


Email: {email}




));
}

export default user;

```

## Tailwind
+ make sure to enbale the tailwind in config to see the change
```js
import Ura from "ura"

function Button() {
const [render, State] = Ura.init();

return render(() => (

Click Me

));
}
```

## Conditions:
- `ura-if`, `ura-elif`, `ura-else`
- you can use them as tags ``, ``, ``
- or you can use as attributes

```js
import Ura from "ura";

function WeatherDisplay() {
const [render, State] = Ura.init();
const [getTemp, setTemp] = State(25); // Default temperature
const [isRaining, setIsRaining] = State(false);

return render(() => (


Weather Conditions



{/* Tag syntax */}
30}>
Heat warning!



Freezing temperatures!



Normal temperature range



{/* Attribute syntax */}
Bring an umbrella! ☔

No rain expected today


{/* Shorthand if statement (ternary) */}

Current temperature: {getTemp()}°C -
{getTemp() > 20 ? " Warm" : " Cool"}


{/* Controls to demo dynamic changes */}

setTemp(getTemp() + 5)}>Increase Temp
setTemp(getTemp() - 5)}>Decrease Temp
setIsRaining(!isRaining())}>
Toggle Rain




));
}

export default WeatherDisplay;
```

## Loops:
- `` tag can be treated as any tag you can style it, add className etc...
```js
function Card() {
const [render, State] = Ura.init();
const [getItems, setItems] = State(["Milk", "Eggs", "Bread", "Fruits"]);

return render(() => (


Grocery Items

{/* Tag syntax with tag won't be shown in the view*/}

{(item, index) => (


{index + 1}. {item}
setItems(getItems().filter((_, i) => i !== index))}>
Remove


)}


{/* ura-loop as attribute div tag will be shown in the view even if the array is empty */}

{(item, index) => (

{index + 1}. {item}
setItems(getItems().filter((_, i) => i !== index))}>
Remove


)}

{/* use map method */}
{getItems().map((item, index) => (


{index + 1}. {item}
setItems(getItems().filter((_, i) => i !== index))}>
Remove


))}

setItems([...getItems(), "New Item"])}>
Add Item



));
}
```

## Component Composition
+ example card component
```js
import Ura from 'ura';

function Card(props, children) {
const [render] = Ura.init();

return render(() => (


{props.title}


{children}

));
}
export default Card;
```
```js
import Ura from 'ura';
import Card from '../../components/Card.js';

function Dashboard() {
const [render] = Ura.init();

return render(() => (


Name: John Doe


Email: john@example.com






  • Posts: 34

  • Followers: 120




));
}
export default Dashboard;
```

## Deploy using docker

1. Build the Project
+ To build the project and generate the necessary Docker configuration files, run the following command:
```bash
npm run build
```
This command will use Nginx to serve your static files and generate a docker directory with the following structure:
```
docker/
├── app/ # Contains all transpiled files (e.g., JavaScript, CSS, etc.)
├── nginx/ # Contains the nginx configuration file
│ └── nginx.conf
├── Dockerfile # Dockerfile to build the application container
├── docker-compose.yml # Docker Compose file to set up and run the container
└── Makefile # Makefile to run Docker container
```

2. Build and Run the Container

+ After running npm run build, navigate to the docker directory:
```bash
cd docker
```
+ To start the Docker container, run:
```bash
make
```
3. Stop the Container
```bash
make down
```

4. Clean Up Volumes and Remove Docker Images
```
make clean
```

5. Check Nginx Configuration
+ The Nginx configuration is in docker/nginx/nginx.conf. It serves the transpiled files
+ Check the port in nginx.conf (e.g., listen 17000). The port is automatically selected during the build process by choosing the available one.
+ After starting the container, open your browser and go to:
```
http://localhost:17000
```