# Introduction

# What is Ovee.js

Ovee.js is a lightweight, component-based JavaScript framework built to work with server-side rendered markup. It's meant to bring the modern toolset to the traditional workflow.

# Installation

yarn add ovee.js

# or

npm install --save ovee.js

Additionally, lit-html is a required peer dependency, that needs to be installed as well, so if you don't have it in your project yet, install it, using:

yarn add lit-html

# or

npm install --save lit-html

# Browser Support

Ovee.js used with babel supports all modern browsers. Currently it's meant to be used with a bundler to provide support for novel features like MutationObserver and decorators.

# Quick Start

We made a quick start setup that can help you go up and running with a few commands. It uses Vite, and excluding one simple example, is quite plain, so feel free to test Ovee there or even use it as a base for your future project!

To install it:

npx degit owlsdepartment/ovee-starter my-project

cd my-project
# install dependencies
yarn
# and run it!
yarn dev # or serve

# Getting Started

Ovee.js app lives around a root element. It acts as a container for all its components and modules. Let's take a look at some code.

<div id="app"></div>
import { App } from 'ovee.js';

const root = document.getElementById('app');
const app = new App();

app.run(root);

This way we get a working application. It doesn't do much so far, but is ready to work. It will be our starting point to do some more interesting stuff.

# Lifecycle

The app starts its lifespan as soon, as you call app.run(root) method. You should register all components and modules before that point. As soon as you call app.run(root), the app object starts to observe all DOM changes within the root container (using MutationObserver).

# Components

Component objects are being automaticaly initialized as soon as matching selector appears in DOM and destroyed when such node is removed. Component API exposes lifecycle hooks.

You can find more info in Component Lifecycle section of Component documentation.

# Modules

Modules are initialized at app.run(root). For each module, always only a single instance is initialized, and it lives until the app gets destroyed. Module API exposes lifecycle hooks.

You can find more info in Module Lifecycle section of Module documentation.

# Destroying the app object

In typical use case, the app lives until the user closes the browser tab. In such case, there's no need to destroy it. In more complex cases, like multi-root apps, you may need to clean up the app object. In such case, you should call app.destroy(). It will dispose all components and modules automaticaly.

# Decorators

Ovee.js uses ECMAScript decorators quite heavily. Despite this JS feature it's still in a proposal state, we've decided to utilize it as it brings amazing clarity to component code. You can find out more about ES decorators notation here.

# Initialization

As mentioned in Getting Started section, App object acts as a spine of the application. It provides two ways of registering components and modules. You can do it either using options objects passed into constructor:

import { App } from 'ovee';

import OveeBarba from '@ovee.js/barba';

import TodoList from './components/TodoList';
import TodoListItem from './components/TodoListItem';

const app = new App({
    components: [
        TodoList,
        TodoListItem
    ],
    modules: [
        OveeBarba
    ]
});

Alternative notation is to use registerComponent() for single component or registerComponents() for multiple components and use() for modules. Example:

import { App } from 'ovee.js';

import OveeBarba from '@ovee.js/barba';

import TodoList from './components/TodoList';
import TodoListItem from './components/TodoListItem';

const app = new App();

app.registerComponent(TodoList);
app.registerComponent(TodoListItem);
// OR
app.registerComponents([
    TodoList,
    TodoListItem
]);

app.use(OveeBarba);

# Passing options into components

You can pass options object while registering a component. This object will be available in all component instances. Let's show this once again as an example, as it says more than a thousand words:

const app = new App({
    components: [
        ContactForm,
        [Slider, {
            loop: true,
            speed: 500
        }]
    ]
});

app.registerComponent(NavToggle, {
    toggleClassName: 'menu__is-visible'
});

# Passing options into modules

Similarly to components, you can pass options object while registering a module. This object will be available in a module instance.

const app = new App({
    modules: [
        [OveeBarba, {
            transitions: [
                defaultTransition
            ]
        }]
    ]
});

app.registerComponent(DetectBrowsers, {
    addClassesToHtml: true
});

# Configuration

You can configure the App object a little bit. In most cases you won't need to change these options, but it's worth to tell you that you can. You can pass config object into constructor options, or use setConfig(config) method. Configuration is being merged with the defaults, so you don't need to pass all the options if you only want to change one.

const app = new App({
    options: {
        namespace: 'ymce',
        productionTip: false
    }
});

# Available configuration options

Option Default Value Description
namespace 'ovee' during its lifecycle, the framework uses namespacing prefixes e.g. for css classes it adds, and events it triggers and listens to.
productionTip process.env.NODE_ENV !== 'production' displays a tip on console if the app is not built for production to remind you, that development build is not optimized.
global window global object, in browser it should be set to window
document document document object, leave it as is unless you really know what you're doing

# Retreiving configuration

You can access the current App configuration using getConfig() method. Please mind, that it returns a copy of the configuration, so changing anything in this object won't mutate the current configuration.

Last Updated: 2/22/2023, 2:05:09 PM