NodeJS SVG to Animated Gif

Needed an to take an SVG and individually grab frames of the same SVG and place them into an animated gif. This lib simplifies it to await gif.addFrame(svgString, delay).

img-min--1--1

The SvgGif util below simplified the use of gif-encoder, convert-svg-to-png, and png-js.

const fs = require('fs');
const GifEncoder = require('gif-encoder');
const { convert } = require('convert-svg-to-png');
const Png = require('png-js');

function decode(data) {
    return new Promise((resolve) => {
        new Png(data).decode((pixels) => {
            resolve(pixels);
        });
    });
}

class SvgGif {
    constructor({ width, height, fileName = 'img.gif', repeat = 0 }) {
        // Create GIF
        this.gif = new GifEncoder(width, height);
        this.gif.setRepeat(0);
        this.gif.on('error', (err) => console.log(err));

        // Collect output
        const file = fs.createWriteStream('img.gif');
        this.gif.pipe(file);
        this.gif.writeHeader();
    }

    async addFrame(svg, delay = 1000) {
        this.gif.setDelay(delay);
        const data = await convert(svg);
        const pixels = await decode(data);
        this.gif.addFrame(pixels);
    }

    finish() {
        this.gif.finish();
    }
}

module.exports = SvgGif;

Example usage:

const SvgGif = require('./SvgGif');

const width = 1280;
const height = 720;

var svg = `
    ... place full svg file contents here ...
`;

(async () => {

    const gif = new SvgGif({
        width,
        height,
        fileName: 'img.gif'
    });

    console.log(`Generating...`);
    
    // Render 1 frame for 1 second
    await gif.addFrame(svg, 1000);
    
    // Modify SVG here and render frame
    await gif.addFrame(svg, 1000);
    
    // Done
    gif.finish();
    console.log(`Done.`);
})();

LWC and GitHub Actions / Pages

Sharing what you create with lwc.dev can be as easy as adding a GitHub Action to deploy to GitHub Pages.

  • GitHub Pages are static pages hosted at user.github.io/
  • These static files live in your github.com/user/user.github.io repo.
    • Create a blank repo with this name if it doesn't exist.
  • GitHub Actions are .yml files in the .github/workflow/file.yml directory of your project. These can subscribe to events, like a user pushing to the master branch, and then spin up a docker container to do anything.

The script below is going to do a few things.

  • Checkout your projects files
  • npm install
  • npm run build (build LWC application to /dist)
  • Clone our user.github.io repo.
  • Copy /dist/* to a folder in the user.github.io/ folder.
  • (optional, we need non-absolute paths in index.html, so remove / at the start of urls)
  • Git Add + Commit + Push to user.github.io.

The script will also need a few secrets added. Once a secret is set in the repo settings tab it becomes readonly.

  • GIT_USER - Your username or bot account
  • GIT_TOKEN - Personal Token (treat this like a password!)
  • GIT_EMAIL - Used for commit.
  • GIT_NAME - Your name or a "Bot"

Secrets are also removed from logs. For instance if you don't want your email or name in the logs, save them as secrets!
You can use any user as long as they have write access to the repository.

name: CD

on:
  push:
    branches:
    - master

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Checkout
      uses: actions/setup-node@v1
      with:
        node-version: 10.x
    - name: npm install, build, and deploy
      run: |
        npm install
        npm run build
        git clone https://${{ secrets.GIT_USER }}:${{ secrets.GIT_TOKEN }}@github.com/Templarian/templarian.github.io
        cp -rf dist/. templarian.github.io/lwc-ui/
        cd templarian.github.io
        git config --global user.email "${{ secrets.GIT_EMAIL }}"
        git config --global user.name "${{ secrets.GIT_NAME }}"
        sed -i 's/"\//"/g' lwc-ui/index.html
        git add .
        git commit -m "Deploy lwc-ui"
        git push

In the above script replace templarian with the name of your user. The secret GIT_USER could be used here, but it's important to illustrate that another user with access could be used. Such as a bot account.

Similar GitHub Actions can be used to sync files between repositories. You can also parse the commit message and only build when a certain word is found.

Debug LWC Jest Tests with VS Code

It's as easy as adding a launch.json in the .vscode folder.

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
      {
        "type": "node",
        "request": "launch",
        "name": "Jest Tests",
        "program": "${workspaceRoot}/node_modules/.bin/jest",
        "cwd": "${workspaceRoot}",
        "args": ["-i", "--runInBand", "${relativeFile}", "--no-cache"]
      }
    ]
  }
  

On the left select the debug menu, and the play while viewing the .spec.js file you wish to debug. Be sure to place a breakpoint first.

Update to @mdi/react v1.1.0

Spent this Saturday going through a large backlog of Open Source tasks. One of them is fixing a bug in @mdi/react.

View @mdi/react on NPM

This library is used by ReactJS developers to quickly render icon path data with a lot of nice helper props.

  • Fixed a bug with horizontal and vertical being ignored.
  • Added support for spin prop that allows a negative value.
    • Negatives values will rotate counterclockwise -X seconds.
    • Positive values rotate clockwise.
    • Still defaults to 2 seconds rotation speed clockwise for true.
  • Fixed a edge case nesting horizontal and spin in a stack. I doubt anyone ran into this since this was also broken by the first bug.
<Icon path={mdiLoading} spin={-2}/>

This component should be considered feature complete now. This means all new code changes will be to optimize the Unit Tests and ensure the outputted markup is as optimized as possible.