An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

栏目: IT技术 · 发布时间: 4年前

内容简介:An ultra-fast and tiny (5.1 kB) browser based compiler for JSX / React.A single JavaScript fileSource:

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

An ultra-fast and tiny (5.1 kB) browser based compiler for JSX / React.

What is it? :tada:

A single JavaScript file jsxLoader.js that compiles / transpiles JSX to JS for modern browsers and for old browsers it will download and use Polyfills and Babel Standalone.

Source: https://github.com/dataformsjs/dataformsjs/blob/master/js/react/jsxLoader.js

Demo: https://www.dataformsjs.com/examples/hello-world/en/react.htm

Why :question:

The jsxLoader.js script was created to provide a fast method for including React with JSX on web pages and web apps with no build process, CLI tools, or large dependencies needed; simply use React with JSX in a webpage or site and included needed CDN or JavaScript files.

CLI Development tools such as webpack , babel , and create-react-app are great but they do not make sense for all sites, web pages, and development workflows; and Babel Standalone is huge to include on each page - 320 kB when gzipped and 1.5 MB of JavaScipt for the Browser to process. With a browser based options for JSX you can easily include React Components on any page without having to build the entire site using React or JSX.

Old Browsers typically account for less than 5 % of users for most sites - mostly IE and old iOS/Safari. Generally if someone is browsing from IE they are used to slow pages and if someone is browsing from an old iPhone or iPad they end up with many broken sites so simply having a site work is good even if it's slow. This script provides a good trade-off - fast for most users with modern browsers and it still works on old browsers.

Prior to the jsxLoader.js being created all React demos on DataFormsJS used Babel Standalone. Babel Standalone is great for prototyping and works with React DevTools however due to its size it takes a lot of memory and causes an initial delay in loading the page so it’s generally avoided on production sites. On mobile devices the delay can be many seconds. Here is an example of before and after performance differences when using Babel vs jsxLoader .

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

Performance is great because jsxLoader compiles code to modern JS for modern browser and because it’s a minimal compiler it’s very fast to process.

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

Can it be used for production apps and sites? :rocket:

Yes, it was created for this reason.

The script is tested with a variety of devices and browsers including the following:

  • Modern Browsers:
    • Chrome
    • Safari - Desktop and iOS (iPhone/iPad)
    • Firefox
    • Edge (Chromium and EdgeHTML)
    • Samsung Internet
    • UC Browser
    • Opera
  • Legacy Browsers:
    • IE 11
    • Safari iOS

In addition to React it also works and is tested with the React alternative libary Preact.

The jsxLoader.js script is very small to download (5.1 kB - min and gzip) and compiles code very fast (often in milliseconds for each JSX script).

How to use? :star2:

<!-- Include React on the Page -->
<script src="https://unpkg.com/react@16.12.0/umd/react.production.min.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.production.min.js" crossorigin="anonymous"></script>

<!--
    Include the DataFormsJS JSX Loader.
    Either [jsxLoader.min.js] or [jsxLoader.js] can be used.
-->
<script src="https://cdn.jsdelivr.net/npm/dataformsjs@3.6.1/js/react/jsxLoader.min.js"></script>

<!--
    Include JSX components and scripts using [type="text/babel"].
    This is the same method that would be used with Babel Standalone.
-->
<script type="text/babel" src="https://cdn.jsdelivr.net/npm/dataformsjs@3.6.1/js/react/es6/JsonData.js"></script>
<script type="text/babel">

    class HelloMessage extends React.Component {
        render() {
            return (
                <div>Hello {this.props.name}</div>
            );
        }
    }

    ReactDOM.render(
        <HelloMessage name="World" />,
        document.getElementById('root')
    );

</script>

Demos :globe_with_meridians:

React

Preact

Rax An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

Try it online in the Code Playground :rocket:

https://www.dataformsjs.com/en/playground

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

Will it work for all sites and apps? :dizzy:

The script is intended to handle most but not all JSX Syntax. An overall goal is that most JSX should work with only a slight update if needed on edge cases.

Once this script was created all React demos for DataFormsJS were able to use it instead of Babel without having to make any JSX code changes and this is expected for most sites.

Handling node require and import statements

Because JSX is converted directly to JS for the browser, code that uses require and import statements for node will not work in the browser. However the jsxLoader.js script provides a flexible API that can be used to customize the generated code so that import and require statements or other code can be handled by the browser.

For example, if you use the following in your JSX Code:

import { useState } from 'react';

Then you have two options:

  1. Remove it and use React.useState instead of useState in your code. This works because React is a global variable for the browser.
const [count, setCount] = React.useState(0);
  1. Add a custom find and replace update.
<script>
    jsxLoader.jsUpdates.push({
        find: /import { useState } from 'react';/g,
        replace: 'var useState = React.useState;'
    });
</script>

Often components, functions, etc that need to be imported for node will exist as global variables in the browser so for browser based JSX development you can often exclude import and require statements.

By default the following import is automatically handled:

import React from 'react';

Using JavaScript that only has partial browser support

Another issue is using JavaScript that only works in some modern browsers. For example using Class fields / properties will work in some Browsers (Chrome, Firefox) but not work with other Browsers (As of 2020 this includes Safari, Edge (EdgeHTML), and Samsung Internet).

class App extends React.Component {
    // This version works with Chrome and Firefox,
    // but will cause errors with many mobile devices
    state = {
        message: 'Hello World',
    };

    componentDidMount() {
        window.setTimeout(() => {
            this.setState({
                message: 'Updated from Timer'
            });
        }, 500);
    }

    render() {
        return (
            <div>{this.state.message}</div>
        )
    }
}
class App extends React.Component {
    // By defining class properties in the `constructor()`
    // the code will work on all modern browsers.
    constructor(props) {
        super(props);
        this.state = {
            message: 'Hello World',
        };
    }
}

This also includes the JavaScript spread syntax which only has partial support for modern browsers. For example ...numbers will work with Chrome, Firefox, etc but it will not work with all versions of Edge or the UC Browser which is widely used in Asian Countries. If you use the spread syntax in your app see additional notes in the [Advanced Usage] section of this document.

Code Splitting :scissors:

A seperate DataFormsJS React Component <LazyLoad> exists and allows for browser based apps to dynamically load *.js , *.css , and *.jsx scripts the first time they are used by a component.

Examples from the Places Demo App:

In the below example all 3 files will be downloaded when the Component LoadMapAndPage is mounted. While the scripts are being loaded a Component <ShowLoading> will be displayed and once all scripts are finished downloading then the Component <ShowCity> will be dynamically created. In this example a string value is used for ShowCity because the Component will not exist until the file place-react.jsx is downloaded.

Additionally the added properties data and params will be passed as props to ShowCity ; any custom properties used will be passed to the child element. If ShowCity already exists before calling <LazyLoad> then isLoaded={<isLoaded />} could be used.

function LoadMapAndPage(props) {
    return (
        <LazyLoad
            scripts={[
                'https://unpkg.com/leaflet@1.5.1/dist/leaflet.css',
                'https://unpkg.com/leaflet@1.5.1/dist/leaflet.js',
                './html/place-react.jsx',
            ]}
            isLoading={<ShowLoading />}
            isLoaded="ShowCity"
            data={props.data}
            params={props.params} />
    );
}

By default all scripts are downloaded asynchronously without waiting for ealier scripts to complete. This option is the fastest however it will not work for all code. In the below example chosen.jquery.min.js must be loaded after jquery-3.4.1.min.js so the property loadScriptsInOrder is used to tell LazyLoad to load scripts in sequential order.

Additionally the below snippet shows that {children} can be used instead of the isLoaded property.

<LazyLoad
    isLoading={<ShowLoading />}
    loadScriptsInOrder={true}
    scripts={[
        'https://code.jquery.com/jquery-3.4.1.min.js',
        'https://cdn.jsdelivr.net/npm/chosen-js@1.8.7/chosen.css',
        'https://cdn.jsdelivr.net/npm/chosen-js@1.8.7/chosen.jquery.min.js',
        'css/countries-chosen.css',
    ]}>
    {children}
</LazyLoad>

Advanced Usage and Internals :microscope:

You can view the code here ! All code is in a single file and includes many helpfull comments to allow for understanding of how it works.

The jsxLoader script provides a number of properties and functions that can be used to customize how it runs. Below are the most common uses.

// View compiler speed for each script in DevTools console
jsxLoader.logCompileTime = true;

// View the generated code for each script in DevTools console
jsxLoader.logCompileDetails = true;

// Call this if using Preact instead of React. Additionaly if your Preact
// app has unexpected errors when using it you can easily copy, modify, and
// use a custom version of the function so that it works with your app.
jsxLoader.usePreact();

// Add custom file and replace logic for your app or site.
jsxLoader.jsUpdates.push({
    find: /import { useState } from 'react';/g,
    replace: 'var useState = React.useState;'
});

// Additional properties and options exist and can be viewed
// in the source of the [jsxLoader.js] file.

jsxLoader.logCompileTime

When using jsxLoader.logCompileTime the time it takes to compile each script will be logged to the DevTools console.

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

jsxLoader.logCompileDetails

When using jsxLoader.logCompileDetails full details of the main compiler steps will be logged to the DevTools console. This includes:

  • Tokens generated from Lexical Analysis
  • Abstract Syntax Tree (AST) generated from the Tokens
  • Generated Code from the AST

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

Use Babel for Apps that include the Spread Sytnax

If you have a site that uses code like this <Greeting {...props} /> the JSX Loader will convert it to React.createElement(Greeting, ...props) for modern browsers however not all modern browsers support this syntax. This is particularly important if your site is viewed by users in Asian Countries that use the UC Browser (as of 2020) or viewed by users who use Edge (Default Browser in Windows 10).

There are several options:

  1. Avoid using the spread syntax
  2. Use code shown in the snippet below so that Babel will be used for Browsers which do no support the spread syntax
jsxLoader.evalCode = '"use strict"; const { id, ...other } = { id:123, test:456 };';

How JS Code is added to the Page

The jsxLoader.js script runs on the Document DOMContentLoaded event and first checks the environment to determine if polyfills are needed and if Babel should be used. It then downloads JSX Code (or reads inline JSX code), compiles it to regular JavaScript, and adds it back to the page as JavaScript in the <head> element.

Scripts added on the page will have a data-compiler attribute with the value of either jsxLoader or Babel to indicate which compiler was used. If the script was downloaded then it will include the data-src attribute with the URL of the original JSX script.

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

Local Development

Typically the minimized version jsxLoader.min.js will be used for production while the jsxLoader.js is the full version of the script that is used for development. It has no dependencies and is browser based so once it is included on a page you can step through the code using Browser DevTools.

Building [jsxLoader.min.js] from [jsxLoader.js]

All *.min.js files in DataFormsJS are built from the full file version of the same name using a build script that depends on uglify-js , uglify-es , and Babel . The jsxLoader.min.js can be built using only uglify-js .

# From project root
node install
node run build

Or run the .\scripts\build.js script directly: node build.js .

Unit Testing

Unit Tests for jsxLoader.js run from a browser using Mocha. Often React Components are tested from a mock browser environment using Jest, however it’s important that the jsxLoader.js be tested from an actual browser so that it can be verified in as many environments as possible and because it downloads and Polyfills and Babel for some browsers.

This method also helps verify that the behavior of the compiled JS code from jsxLoader.js matches the same result from Babel. For example modern browsers need to be confirmed as well as IE 11 (which uses Babel).

# Install Node
# https://nodejs.org

# Download [dataformsjs/dataformsjs] repository:
# https://github.com/dataformsjs/dataformsjs

# Start Server from project root.
# The local test and demo server for DataFormsJS has no dependencies
# outside of built-in Node.js objects.
node ./test/server.js

# Or run the file directly
cd test
node server.js

# View the unit test site and run tests:
# http://127.0.0.1:5000/

The image below shows what the Unit Test page looks like. When testing with a modern browser jsxLoader will appear in the upper-left-hand corner of the screen.

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

When testing with a legacy browser such as IE 11 Babel will be shown along with (Polyfill Downloaded) .

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

If a modern browser is being tested that doesn't support that spread syntax then a helpful warning will be displayed because it will cause some tests to fail. Additionally (Polyfill Downloaded) will appear for modern browsers that need to download Polyfills (typically if Promise.prototype.finally is missing).

An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

Known Issues :warning:

  • In general if a known issue requires a lot of code it will likely not be supported because this script is intended as a small and fast JSX parser/compiler and not a full featured JavaScript parser/compiler.

  • Error messages may not be very friendly for some unexpected syntax errors so using linting in a Code Editor is recommened during development to avoid errors from jsxLoader.js . If you develop with Visual Studio Code or other popular editors this should happen automatically. If you have syntax errors with the generated code and it’s not clear why then using Chrome DevTools is recommended (or Edge built with Chromium). Because generated JavaScript is added back in dynamic elements most Browsers will display the wrong location of the error but latest versions of Chrome and Edge will often show it in the correct location. An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS

  • Minimized for loops may cause issues: for(n=0;n<m;n++) as the <m;n++) will likely be parsed as an element. However if a full file is minimized it will be processed as JavaScript which means minimized Components will generally work by default.

  • Sometimes extra child whitespace is generated in child nodes of React.createElement('element', props, ...children) compared to what would be created when using Babel. Generally this doesn’t happen often but it has been found in the log demo page . This issue has no visual effect on the page, no performance decrease, and doesn't happen often so it's considered acceptable.

  • Text that looks like elements inside of complex nested template literals (template strings) may cause parsing errors or unexpected results:

    Example parsed correctly:

    const testHtmlString = `${`'<div>test</div>'`}`

    Result: testHtmlString = "'<div>test</div>'"

    Example parsing error:

    const testHtmlString = `${`<div>test</div>`}`

    Result: testHtmlString = 'React.createElement("div", null, "test")';


以上所述就是小编给大家介绍的《An ultra-fast and tiny (5.1 kB) browser-based JavaScript compiler for converting JSX to JS》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人月神话

人月神话

[美] 弗雷德里克·布鲁克斯 / 汪颖 / 清华大学出版社 / 2002-11 / 29.80元

作者为人们管理复杂项目提供了颇具洞察力的见解,既有很多发人深省的观点,也有大量的软件工程实践。书中的内容来自布鲁克斯在IBM公司System 360家族和OS 360中的项目管理经验。初版的20年后,布鲁克斯重新审视了他原先的观点,增加了一些新的想法和建议。新增加的章节包括:原著中一些核心观点的精华;在经过了一个时代以后,Brooks博士对原先观点新的认识;1986年的经典文章《没有银弹》;对19......一起来看看 《人月神话》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具