npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

javel

v0.1.7

Published

Simple, lightweight and customisable Laravel models in your JavaScript

Readme

Javel

🎁 Wrap your plain JavaScript objects into customizable Laravel-like models. Read introduction article.

cover

Installation

npm i javel -D

Overview

import Model from 'javel'

class Article extends Model {/* ... */}

await Article.all({ /* request */ })                        // => [ Article* ]
await Article.paginate({ query: { page: 2 } })              // => { data: [ Article* ], current_page: 2, ... }
await Article.find(1)                                       // => Article { id: 1, ... }

let article = await Article.create({ name: 'My article' })  // => Article { id: 2, name: 'My article' }
await article.update({ name: 'My updated article' })        // => Article { id: 2, name: 'My updated article' }
await article.delete()                                      // => Deleted from the server

article = new Article({ name: 'My draft blog post' })
article.name = 'My new blog post'
await article.save()                                        // => Article { id: 3, name: 'My new blog post', ... }

Getting started

Start by creating your base model that all other models will extends from. In there you can override any logic you want or, even better, attach additional behavior using mixins (see below).

import { Model as BaseModel } from 'javel'

export default class Model extends BaseModel {
    //
}

Typically, in this base model, you would set up how to reach your server by overriding the baseUrl and makeRequest methods like this:

export default class Model extends BaseModel {
    baseUrl () {
        return '/api'
    }
    makeRequest ({ method, url, data, query }) {
        return axios({ method, url, data, params: query })
    }
}

Note that baseUrl defaults to /api and that makeRequest will automatically use axios if it available in the window (which is the case by default in Laravel).

Next, create specific models for your application.

import Model from './Model.js'

export default class Article extends Model {
    // Your logic here...
}

Finally you will likely want to configure which URL should be used for each actions (find, create, update, etc.). You might also want to add some behavior right before or after requests are made and customize how to handle the response. You can learn all about this in the documentation of the MakesRequests mixin.

A chain of mixins

Javel uses the mixwith library to separate each functionality of a Model into dedicated mixins (comparable to how Eloquent uses traits in Laravel). For the sake of convenience, Javel exposes the mixwith's API directly:

import { Model as BaseModel, Mixin, mix } from 'javel'

// Create a mixin
const ImmutableModels = Mixin(superclass => class extends superclass {
    //
})

// Use a mixin
class Model extends mix(BaseModel).with(ImmutableModels) {
    //
}

You can of course combine as many mixins as you want.

import { Model as BaseModel, mix } from 'javel'
import { MixinA, MixinB, MixinC } from './mixins'

// Use a mixin
class Model extends mix(BaseModel).with(MixinA, MixinB, MixinC) {
    //
}

Note that the order in which you use your mixins is important. The mixins will be applied using inheritance from right to left. Therefore the previous example is comparable to:

class MixinA extends BaseModel {}
class MixinB extends MixinA {}
class MixinC extends MixinB {}
class Model extends MixinC {}

Check out the lifecycle of a base model before creating your own mixins.

Mixins included in Javel's Model

By default, the base Model provided by javel includes the following mixins (in this order, i.e. the lower overrides the higher). You can learn more about each of them by reading their dedicated documentation.

  • HasAttributes Defines the basis of getting and setting attributes on a Model and provide some useful methods like primaryKey, exists, is, clone, etc.
  • HasRelationships Enables models to configure their relationships with each other so that their attributes are automatically wrapped in the right model.
  • KeepsParentRelationship Ensures each child relationship keeps track of its parent and how to access itself from it. This enables models to climb up the relationship tree and even remove themselves from their parent when deleted.
  • MakesRequests Introduces async actions (find, create, update, etc.) to conveniently request the server and provides all the hooks necessary to customize how to handle your request/response proctol for each model.

Extra mixins available

Javel also provides some additional mixins that can be useful to plug in or to get inspired from when writing your own. Don't hesitate to PR your best mixins and share it with us.

  • GeneratesUniqueKey Attaches a unique key to every new model instanciated. If the model has a primary key available, the primary key will be used instead of generating a new unique key.
  • UsesMethodFieldWithFormData Transforms the update action to use the POST method with the _method=PATCH field when the provided data is an instance of FormData.
  • IntegratesQueryBuilder An easy way to build a query string compatible with "spatie/laravel-query-builder" (Has dependencies: js-query-builder).

Optional dependencies

Some extra mixins have additional dependencies that need to be resolved. For example, some mixins could wrap a third party library to make it work with Javel out-of-the-box. Because these mixins are optional (you can choose not to add them), their dependencies must also be optional so that you don't end up loading lots of dependencies you don't need.

This means, when you do decide to pull in a mixin that has dependencies, you have to install them yourself and tell Javel how to access it, like this:

npm i third-party-library
import ThirdPartyLibrary from 'third-party-library'
import { Model as BaseModel, mix, SomeMixinThatUsesThirdPartyLibraries, registerModule } from 'javel'

registerModule('third-party-library', ThirdPartyLibrary)

class Model extends mix(BaseModel).with(SomeMixinThatUsesThirdPartyLibraries) {
    //
}

Note: This behaviour has been designed as a workaround of webpack's optional externals which unfortunately creates warnings when optional dependencies are not present.