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 🙏

© 2024 – Pkg Stats / Ryan Hefner

riotjs-simple-typescript

v0.5.0

Published

A way to work with TypeScript in RiotJS which also works fine with unit testing

Downloads

11

Readme

riotjs-simple-typescript

A slightly different take on working with TypeScript in RiotJS.

Write controllers in TypeScript and include their compiled .js version from the <script> tag in the .riot templates.

Use mocha or jest to test TypeScript controller together with headless virtual rendering of .riot templates.

Benefits

1. Write controllers in `.ts` files.
2. Test controllers using traditional unit testing framworks, together with virtual HTML rendering of the `.riot` template.
3. Always have `this`, `props` and `state` properly typed for all components.
4. Clear seperation of controllers and views (if you are into this).

Caveats and design choices

1. Be aware of that in the `.riot` template there is NO type checking when accessing `this`, `props`, or `state`.

2. Keep all logic out of the `.riot` templates.
    OK: `<a onclick={(e) => update({name: e.target.value})}>`
    OK: `<a onclick={handleClick}>`
    AVOID: `<a onclick={(e) => {this.myVar = e.target.value; state.count++; update()}}>`

    This is so that the unit tests can focus on testing the controller and not the view.

3. Be aware of that when unit testing and virtually rendering the `.riot` template using `linkedom` riot expression are NOT executed in the template meaning that HTML element value initializing will not run which may or may not effect your tests.
    `<input id="name" value={props.name} />` when read from the virtual DOM as `this.$("#name").value` in a unit test will be the string "{props.name}" (not the value of props.name as expected).

    So, if reading from DOM input element in the unit tests first adopt the pattern in the controller class to init the DOM element value using `this.$(...).value = props.name`.
    Do that in `onMounted` as: `this.$("#name").value = props.name`.

4. The `.riot` template `<script>` tag does two things:
    1. Import any CSS which webpack is to process:  
        `import "./my-component.css`

    2. Import and return instance of the controller class:  
        ```js
        import {MyComponent} from "./MyComponent";
        return new MyComponent();
        ```

        Note that this replaces the common riotjs pattern of:  
        ```js
        export default {
            onMounted(props, state) {}
            ...
        }
        ```

    Also `<script>` tags do NOT run in testing when rendering with `linkedom`.

5. Since riotjs expression are not run in the templates when testing conditionals as `<div if={state.visible}>` will not do anything and the `<div>` will be present always.
    Also `<template>` and `</template>` tags are cut from the HTML and not present in the virtually rendered DOM, however their content is present.

Installation

npm i riotjs-simple-typescript

Usage

In your component:

./src/my-component.riot:

<my-component>
    <div>
        <p>{state.text}</p>
    </div>

    <style>
        p {
            font-size: 10em;
        }
    </style>

    <script>
        import "./my-component.css";

        // This will implicitly import the compiled .js version of the controller.
        import {MyComponent} from "./MyComponent";

        return new MyComponent();
    </script>
</my-component>

./src/MyComponent.ts:

import {
    RiotBase,
} from "riotjs-simple-typescript";

export interface MyComponentProps {
    // Put expected props fields here
}

export interface MyComponentState {
    text: string;
}

export class MyComponent extends RiotBase<MyComponentProps, MyComponentState> {
    public onMounted(props: MyComponentProps, state: MyComponentState) {
        state.text = "Hello World from TypeScript";

        this.update();
    }
}

Run tsc and let it place all compiled .js files alongside their .ts source files. Riot will pick up the .js file and our unit testing will pick up the .ts file.

Testing

Use the Wrapped class for testing components.

import fs from "fs";  // we use this only to read .riot files from disk.

// NOTE: .ts here to not get the .js version.
// This will require allowImportingTsExtensions to be true for tsc to accept import .ts explicitly.
/
import {MyComponent} from "./MyComponent.ts";  // .ts

import {Wrapped} from "riotjs-simple-typescript";

describe("my-component", function() {
    it("should work, period.", function() {
        const props = {};

        const viewpath = `${__dirname}/my-component.riot`;
        const html = fs.readFileSync(viewpath, "utf-8");

        const wrapped = new Wrapped(MyComponent, html, props);

        assert(wrapped.component.state.text === "Hello World from TypeScript");
    });

    it("should not init values until mounted", function() {
        const props = {};

        const viewpath = `${__dirname}/my-component.riot`;
        const html = fs.readFileSync(viewpath, "utf-8");

        // passing false as fourth argument will not run onBeforeMount and onMounted.
        //
        const wrapped = new Wrapped(MyComponent, html, props, false);

        assert(wrapped.component.state.text === undefined);

        // Will call onBeforeMount and onMounted on the component.
        //
        wrapped.mount();

        assert(wrapped.component.state.text === "Hello World from TypeScript");
    });
});

The Wrapped class has the public field component, mount(), onRender(callback), updateProps(newProps) to help mimic the riotjs environment.

Run the tests with the compiler option set as:

TS_NODE_COMPILER_OPTIONS='{"allowImportingTsExtensions": true}' npx mocha -r ts-node/register

cli-tool

There is a cli-tool called riot-new which can be used to instantiate stubs of components and modal components.

npx riot-new component my-component ./components
npx riot-new modal my-modal ./components

Modals cen be opened as:

MyModal.open(props[, options]).then( result => ... );

License

MIT