react-select.browser.*.js doesn't work from the browser via cdn

Created on 11 Jul 2020  路  10Comments  路  Source: JedWatson/react-select

I'm upgrading from react-select v2 (umd) which was possible to use directly from the browser via the cdn
(there's a recipe how to do it on stackoverflow: https://stackoverflow.com/a/53929535/237105).

What is the proper way (if any) to use v3 this way?

The https://unpkg.com/browse/[email protected]/dist/ distribution has two browser versions
of react-select:

  • react-select.browser.esm.js - which doesn't get imported because browsers don't currently work with bare modules:
<script type="module" src="https://unpkg.com/[email protected]/dist/react-select.browser.esm.js"></script>

Uncaught TypeError: Failed to resolve module specifier "react". Relative references must start with either "/", "./", or "../".

and

  • react-select.browser.cjs.js - which also throws an error because the common.js (https://lucivuc.github.io/browser-cjs/) doesn't
    work with resources located in different directories.

This problem was mentioned several time in other tickets:

Could you please comment on this issue and/or give a workaround for it.

issuenhancement issureviewed

Most helpful comment

Awesome! Great work @ConradSollitt !

I'll close this out and reference this thread for future use interested in having react-select as a standalone.

All 10 comments

Here's what I've come up with so far:

<script type="module">
  import { createElement } from 'https://cdn.pika.dev/react@^16.13.1';
  import { render } from 'https://cdn.pika.dev/react-dom@^16.13.1';
  import Select from 'https://cdn.pika.dev/react-select@^3.1.0';

  const options = [
    { value: 'chocolate', label: 'Chocolate' },
    { value: 'strawberry', label: 'Strawberry' },
    { value: 'vanilla', label: 'Vanilla' }
  ]

  const app = createElement(
    Select,
    {options: options}
  );

  render(app, document.body);
</script>

Everything works except jsx.

A hack that adds jsx support:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />

    <title>Hello React-Select!</title>

    <script src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>

  <body>
    <div id="app"></div>
    <script type="module">
      import { createElement } from 'https://cdn.pika.dev/react@^16.13.1';
      import { render } from 'https://cdn.pika.dev/react-dom@^16.13.1';
      import Select from 'https://cdn.pika.dev/react-select@^3.1.0';
      window.Select = Select;
    </script>
    <script type="text/babel" data-type="module">
      var Select = window.Select;
      const options = [
        { value: 'chocolate', label: 'Chocolate' },
        { value: 'strawberry', label: 'Strawberry' },
        { value: 'vanilla', label: 'Vanilla' }
      ]
      ReactDOM.render(<Select options={options}/>, document.querySelector('#app'));
    </script>
  </body>
</html>

@bladey What is necessary to confirm this bug?

pica.dev doesn't support subdirectories so Async feature is still not available through the browser.

What is the intended way to use react-select from the browser after the UDM format support is deprecated?

Hi @ahatchkins,

I simply need to review it and get it confirmed, I do not have an answer for you right however, apologies.

Another contributor may be able to help.

@bladey ok, thank you!

Great Job @ahatchkins

I had been following the UMD issue on the v3 upgrade guide and wasn't aware that you could do this with Pika/Skypack until I saw your comment.

I tested it and found a few issues and that your demo can be reduced in size as shown below:

  • React was included twice once as <script> and once as import { createElement } ... In the version below I kept the <script>.
  • Your snippet was using Babel Standalone 6 which doesn't support data-type="module" so the version below uses the latest version of Babel Standalone 7. data-type="module" was added in 7.10.0. With Babel 7 the extra <script type="module"> is not needed.
  • For the import I switched to cdn.skypack.dev as cdn.pika.dev now redirects there.

Additionally I currently have babel commented out and am using a small JSX Complier I wrote (5.7 kB gzip and min) jsxLoader.min.js so the demo loads very fast now and still uses JSX. Off topic but I wrote the JSX Compiler so I can use React and JSX in a browser on production sites without having to have a build process or having to include Babel Standalone which is very large.

React Select 3 Demo using CDN
https://awesome-web-react.js.org/examples/select-controls/react-select-3.htm

Working Hello World Demo

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />

    <title>Hello React-Select!</title>

    <script src="https://unpkg.com/[email protected]/umd/react.production.min.js" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js" crossorigin="anonymous"></script>

    <!-- <script src="https://unpkg.com/@babel/[email protected]/babel.js"></script> -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/js/react/jsxLoader.min.js"></script>
  </head>

  <body>
    <div id="app"></div>
    <script type="text/babel" data-type="module">
      import Select from 'https://cdn.skypack.dev/react-select@^3.1.0';
      const options = [
        { value: 'chocolate', label: 'Chocolate' },
        { value: 'strawberry', label: 'Strawberry' },
        { value: 'vanilla', label: 'Vanilla' }
      ]
      ReactDOM.render(<Select options={options}/>, document.querySelector('#app'));
    </script>
  </body>
</html>

Awesome! Great work @ConradSollitt !

I'll close this out and reference this thread for future use interested in having react-select as a standalone.

Thanks @ebonow

Yeah, I'm very happy with this solution as it allows React Select to continue to be used from simple HTML files without a build process. Granted few React developers work that way but it's nice to have the option.

Apparently a related issue to this is accessing CreateableSelect or AsyncSelect as both entry points are located in subdirectories which is not something npm cdn hosts apparently are able to handle.

Perhaps if you can stumble upon getting either to work it could help a few other people.

Got it working! All 3 can be loaded on the page however this example only shows very basic options. When using all 3 on the page at the same time Chrome is showing a DevTools warning regarding a duplicate HTML id.

Code is below. I developed in in a browser using a temporary playground site I created so if you want to try it out just copy and past the code and run online (nothing to install): https://www.dataformsjs.com/en/playground

Anyways I found my previous example resulted in React being loaded twice. Once from <script src="https://unpkg.com/...> and the other time it was also imported by https://www.skypack.dev/

In the version below I add some comments as allowing it to be imported from skypack only allows for a savings of ~50 kB.

One thing to be aware of when including React Select this way is each component react-select, react-select/async, and react-select/creatable results in an additional 20 to 25 requests from skypack for needed dependancies. I still find it to be very fast though so doesn't seem like something to worry about.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Hello React-Select!</title>

    <!--
        This works however React is now included from skypack
        using `import` otherwise it gets requested twice costing
        an extra ~50 kB of JS.
    -->
    <!--
    <script src="https://unpkg.com/[email protected]/umd/react.production.min.js" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js" crossorigin="anonymous"></script>
    -->

    <!--
        Choose one option (both work for this demo)
        [babel.min.js]
            Full Babel Standalone and great for development but very
            large so it typically delays page load by several seconds.
        [jsxLoader.min.js]
            Small 5.7 kB gzip and fast to compile, but only handles JSX.
            https://github.com/dataformsjs/dataformsjs/blob/master/docs/jsx-loader.md
    -->
    <!-- <script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script> -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/js/react/jsxLoader.min.js"></script>

    <style>
        body {
            display: flex;
            justify-content: center;
            padding: 20px;
        }
        section {
            width: 500px;
            margin: 40px 0;
            padding: 10px;
            border: 1px solid black;
        }
        label { font-weight:bold; display:block; margin-bottom:10px; }
    </style>
  </head>

  <body>
    <div id="app"></div>

    <script>
        // Currently required for [react-select/async] and [react-select/creatable].
        // This must run before the `import` statement runs which is why it
        // exists in a regular <script>
        window.process = { env: { NODE_ENV: 'production' } };
    </script>

    <script type="text/babel" data-type="module">
        // Using Latest version of React and a specific version of React Select.
        // If the version number was not included then the latest React Select will be returned.
        import React from 'https://cdn.skypack.dev/react';
        import ReactDOM from 'https://cdn.skypack.dev/react-dom';
        import Select from 'https://cdn.skypack.dev/react-select@^3.1.0';
        import AsyncSelect from 'https://cdn.skypack.dev/react-select@^3.1.0/async';
        import CreateableSelect from 'https://cdn.skypack.dev/react-select@^3.1.0/creatable'

        const options = [
            { value: 'chocolate', label: 'Chocolate' },
            { value: 'strawberry', label: 'Strawberry' },
            { value: 'vanilla', label: 'Vanilla' }
        ]

        const App = function() {
            return (
                <>
                    <section>
                        <label>Select</label>
                        <Select options={options} />
                    </section>
                    <section>
                        <label>AsyncSelect</label>
                        <AsyncSelect defaultOptions={options} />
                    </section>
                    <section>
                        <label>CreateableSelect</label>
                        <CreateableSelect options={options} />
                    </section>
                </>
            )
        }

        ReactDOM.render(<App />, document.querySelector('#app'));
    </script>
  </body>
</html>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

coder-guy22296 picture coder-guy22296  路  3Comments

sampatbadhe picture sampatbadhe  路  3Comments

geraldfullam picture geraldfullam  路  3Comments

Meesam picture Meesam  路  3Comments

mjuopperi picture mjuopperi  路  3Comments