ESNext: Import Assertions (JSON Modules, CSS Modules, …)

Did you know you can import JSON and CSS files just like you import JavaScript Modules? Thanks to Import Assertions, it’s as easy as this:

It’s a regular import statement with an extra assert { "type": … } part added to it. That way you can tell the browser to treat and parse the referenced file to be of a certain type. Once imported you can use the contents further down in your JavaScript code, just like you do with regular ES Module imports.

{
  "appName": "My App"
}
import configData from './config-data.json' assert { type: 'json' };

console.log(configData.appName); // "MyApp"

~

Import Assertions is currently at Stage-3, and is expected to become part of the upcoming ES2022.

💁‍♂️ Stage-3?

The Technical Committee which is concerned with the standardization of ECMAScript (i.e. TC39) has a 5 stage process in place, ranging from stage-0 to stage-4, by which it develops a new language feature.

Stage-3 is the Candidate Stage where the feature is considered complete and only critical changes will happen based on implementation experience. If all goes well the proposal will advance to Stage 4 without any changes, after which it will to become part of the ECMAScript Specification.

Import Assertions are supported in Chromium 91+. For browsers that don’t support it, you can use the es-module-shims polyfill which provides this functionality (and more nice tings)

~

In the most recent episode of CodePen Radio, just a little after the 10-minute mark, you can see host Chris Coyier demonstrate this (along with importing packages directly from Skypack):

The CSS example Chris shows there uses Lit. In a non-framework environment, add the imported styles using Constructed Stylesheets:

import styles from "./styles.css" assert { type: "css" };
document.adoptedStyleSheets = [...document.adoptedStyleSheets, styles];

💡 Do note that adoptedStyleSheets is only supported in Chromium browsers at the time of writing (CanIUse).

~

If you’re wondering why we can’t simply import those files directly, without the assertions, Axel Rauschmayer has the answer:

Browsers never look at filename extensions, they look at content types. And servers are responsible for providing content types for files.

[…]

With an external server, things are even more risky: If it sends the file with the content type text/javascript, it could execute code inside our app.

~

And oh, Import Assertions can be used with dynamic import(). Pass in the assertion as the second parameter:

const configData = await import('./config-data.json', {
  assert: { type: 'json' },
});
console.log(configData.appName); // "MyApp"

~

A future without a Build System is lurking around the corner, especially when you combine these Import Assertions with a follow-up Evaluator Attributes proposal and Import Maps 🤩

~

~

🔥 Like what you see? Want to stay in the loop? Here's how:

quicktype — Convert JSON into gorgeous, typesafe code in any language.

Generate models and serializers from JSON, schema, and GraphQL for working with data quickly & safely in any programming language.

Just paste in some JSON object, choose your output language, and voila!

quicktype — Convert JSON into gorgeous, typesafe code in any language →

How I cut GTA Online loading times by 70%

Interesting read on how GTA Online player t0st got elbow deep into disassembling GTA Online to fix its poor loading times.

After taking a minute to load the common resources used for both story and online modes (which is near on par with high-end PCs) GTA decides to max out a single core on my machine for four minutes and do nothing else.

Disk usage? None! Network usage? There’s a bit, but it drops basically to zero after a few seconds (apart from loading the rotating info banners). GPU usage? Zero. Memory usage? Completely flat…

What, is it mining crypto or something? I smell code. Really bad code.

One of the culprits as he found out: a poorly-implemented JSON parser locking up a single CPU thread as it tries parsing a 10MB JSON file.

Fascinating to see how he’s practically touching in the dark, yet still finding clues and being able to solve them.

Let this be a reminder to not take common tasks/libraries for granted, and also question them when running into performance issues.

How I cut GTA Online loading times by 70% →

Update 2020.03.15: Looks like Rockstar has been paying attention as they will incorporate (the spirit of) these fixes into GTA Online, and have also awarded t0st “Fuc u” 10,000 USD through their Bug Bounty Program.

(Via The Verge)

The Power of the JSON.stringify() replacer parameter

As previously detailed (2013 😱), you can use JSON.stringify()‘s second replacer parameter to pluck specific fields from it, by passing in an array:

var person = {"name":"Jim Cowart","location":{"city":{"name":"Chattanooga","population":167674},"state":{"name":"Tennessee","abbreviation":"TN","population":6403000}},"company":"appendTo"};

JSON.stringify(person, ["name", "company"], 4);
// ~> "{
//      "name": "Jim Cowart",
//      "company": "appendTo"
// }"

As Pawel explains the parameter can also be a function, to manipulate data before it is being returned. This comes in handy if you want to stringify a Set, for example:

const dude = {
  name: "Pawel",
  friends: new Set(["Dan", "Pedro", "Mr Gregory"])
};

const dudeStringified = JSON.stringify(dude, (key, value) =>
  value instanceof Set ? [...value] : value
);

console.log(dudeStringified);
// ~> {"name":"Pawel","friends":["Dan","Pedro","Mr Gregory"]}

The Power of the JSON.stringify() replacer parameter →

💡 Here’s a practicalu use-case: If your data object holds sensitive data, you can use the replacer to filter that part out:

const user = {
  name: 'Bramus',
  password: 'Azerty123',
};

JSON.stringify(user, (key, value) =>
    (key === 'password') ? 'XXXXXXXXXXXX' : value
);
// ~> "{"name":"Bramus","password":"XXXXXXXXXXXX"}"

Faster JavaScript Apps with JSON.parse()

A performance trick that’s been doing rounds on Twitter, now available as a video:

Because the JSON grammar is much simpler than JavaScript’s grammar, JSON can be parsed more efficiently than JavaScript. This knowledge can be applied to improve start-up performance for web apps that ship large JSON-like configuration object literals (such as inline Redux stores).

So instead of assigning a JS object to your store, assign the output of JSON.parse('{…}') to it.

There’s also a Babel plugin named babel-plugin-object-to-json-parse available that can automatically adjust your code for you.

👍 Great to hear Mathias sport the biggest web caveat there is: “It Depends”

JSONbox – Free HTTP based JSON Storage

jsonbox.io lets you store, read & modify JSON data over HTTP APIs for free. Copy the URL below and start sending HTTP requests to play around with your data store.

Oh, this will come in handy for Workshops and quick Proof Of Concepts:

curl -X POST 'https://jsonbox.io/demobox_6d9e326c183fde7b' \
    -H 'content-type: application/json' \
    -d '{"name": "Jon Snow", "age": 25}'

// {"_id":"5d776a25fd6d3d6cb1d45c51","name":"Jon Snow","age":25,"_createdOn":"2019-09-10T09:17:25.607Z"}

Don’t know about the retention policy though 😉

jsonbox.io →

JSON5 – JSON for Humans

JSON isn’t the friendliest to write. Keys need to be quoted, objects and arrays can’t have trailing commas, and comments aren’t allowed — even though none of these are the case with regular JavaScript today.

JSON5 is a proposed extension to JSON that allows these kinds of things. Here’s an example showcasing most of its features:

{
    foo: 'bar',
    while: true,

    this: 'is a \
multi-line string',

    // this is an inline comment
    here: 'is another', // inline comment

    /* this is a block comment
       that continues on another line */

    hex: 0xDEADbeef,
    half: .5,
    delta: +10,
    to: Infinity,   // and beyond!

    finally: 'a trailing comma',
    oh: [
        "we shouldn't forget",
        'arrays can have',
        'trailing commas too',
    ],
}

Note that the JSON5 proposal is in no way official (technically a new MIMEType is required), and – I fear – most likely won’t get that much adoption/traction with things like YAML already floating around…

JSON5 JS Parser →
JSON5 PHP Parser →

JSON Feed

We — Manton Reece and Brent Simmons — have noticed that JSON has become the developers’ choice for APIs, and that developers will often go out of their way to avoid XML. JSON is simpler to read and write, and it’s less prone to bugs.

So we developed JSON Feed, a format similar to RSS and Atom but in JSON. It reflects the lessons learned from our years of work reading and publishing feeds.

The format itself is very easy to read/interpret:

{
    "version": "https://jsonfeed.org/version/1",
    "title": "My Example Feed",
    "home_page_url": "https://example.org/",
    "feed_url": "https://example.org/feed.json",
    "items": [
        {
            "id": "2",
            "content_text": "This is a second item.",
            "url": "https://example.org/second-item"
        },
        {
            "id": "1",
            "content_html": "<p>Hello, world!</p>",
            "url": "https://example.org/initial-post"
        }
    ]
}

A plugin for WordPress is also available.

Announcing JSON Feed →
JSON Feed Plugin for WordPress →

(via ★)

Jasonette – Build cross-platform mobile apps using JSON

Just like how web browsers turn HTML into a web page, Jasonette turns JSON into iOS native components. This lets you build native apps by writing a simple JSON.

Here’s a small snippet/example:

{
    "$jason": {
        "head": {
            "title": "{ ˃̵̑ᴥ˂̵̑}",
            "offline": "true",
            "actions": {
                "$foreground": {
                    "type": "$reload"
                },
                "$pull": {
                    "type": "$reload"
                }
            }
        },
        "body": {
            "header": {
                "style": {
                    "background": "#ffffff"
                }
            },
            "style": {
                "background": "#ffffff",
                "border": "none"
            },
            "sections": [
                {
                    "items": [
                        {
                            "type": "vertical",
                            "style": {
                                "padding": "30",
                                "spacing": "20",
                                "align": "center"
                            },
                            "components": [
                                {
                                    "type": "label",
                                    "text": "It's ALIVE!",
                                    "style": {
                                        "align": "center",
                                        "font": "Courier-Bold",
                                        "size": "18"
                                    }
                                }
                            ]
                        },
                        {
                            "type": "label",
                            "style": {
                                "align": "right",
                                "padding": "10",
                                "color": "#000000",
                                "font": "HelveticaNeue",
                                "size": "12"
                            },
                            "text": "Check out Live DEMO",
                            "href": {
                                "url": "http://www.jasonbase.com/things/xXQ"
                            }
                        },
                        {
                            "type": "label",
                            "style": {
                                "align": "right",
                                "padding": "10",
                                "color": "#000000",
                                "font": "HelveticaNeue",
                                "size": "12"
                            },
                            "text": "Watch the tutorial video",
                            "href": {
                                "url": "https://www.youtube.com/watch?v=S7yGejKIH6Q",
                                "view": "Web"
                            }
                        }
                    ]
                }
            ]
        }
    }
}

The JSON is fetched over HTTP, and then loaded into your app:

This declarative way of working reminds me of one of the approaches I took at work whilst building Culture Club Magazine. Next to the default Story Item types (Cover, Teaser, Article, List, etc.) – each with their specific properties – there’s also a story item type named Custom which accepts a declarative list of components (along with their style, animations, and actions). That list is then translated to actual React components which get rendered inside the story item itself 🙂

Jasonette →
Build cross-platform mobile apps using nothing more than a JSON markup →