Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update webapp guide for browserslist and differential serving changes #780

Merged
merged 3 commits into from
Dec 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 7 additions & 52 deletions src/getting-started/webapp.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ To create a production build in this example you can run `yarn run build` or `np

<body>
<div id="root"></div>
<script src="./index.tsx"></script>
<script type="module" src="./index.tsx"></script>
</body>
</html>
```
Expand Down Expand Up @@ -113,13 +113,7 @@ These bundles are also named in such a way that any non-html assets can be cache

## Browserslist

By default Parcel uses the following browserslist config: [`> 0.25%`](https://browserl.ist/?q=%3E+0.25%25) this will be a good default for most applications.

### Why configure browserslist

Having a custom browserslist ensures you are in full control of which browsers your application supports, for example you need to support IE 11, than you can define: [`> 0.25%, ie 11`](https://browserl.ist/?q=%3E0.25%25%2C+ie+11). This will ensure IE 11 will always work regardless of the market percentage it will have in the future.

On the other side it is also useful for reducing bundle size as supporting a lot and outdated browsers results in a lot of polyfills, for example if you don't need to support IE 11 or Opera Mini you can use [`> 0.25%, not ie 11, not op_mini all`](https://browserl.ist/?q=%3E+0.25%25%2C+not+ie+11%2C+not+op_mini+all) which should in turn reduce bundle size, which results in faster load times and happy users/customers.
By default Parcel does not perform any code transpilation. This means that if you write in ES2020 syntax, that's what Parcel will output. You may wish to support older browsers that don't support these syntax features natively, however, which you can do by configuring a browserslist.

### How to configure browserslist

Expand All @@ -129,56 +123,13 @@ You can find more information over in the [Browserslist repo](https://github.com

In our configuration section, we explain how you can set [targets](/getting-started/configuration/#targets) for configuring Parcel.

## Differential Serving

Parcel also supports differential serving, which means you can serve a different bundle to modern browsers as you do to old browsers. This results in faster load time for newer browsers as the bundle size will be a lot smaller.

You don't have to add any config to make this work, the only thing you have to do is add a script tag to your HTML file. Parcel automatically takes care of the browserslist target by implicitly removing all browsers from your (defined) browserslist that do not support esmodules.

To utilise this, you need to have two script tags in your HTML file: one with `type="module"` and one for older browsers with the `nomodule` attribute.

You can find an example of such a html file below.

{% sample %}
{% samplefile "src/index.html" %}

```html/11,13
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Differential Serving Example</title>
</head>

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

<!-- This script tag will get a reference to the bundle with targetting your defined browser target -->
<script nomodule src="./index.tsx"></script>
<!-- This script tag will get a reference to the esmodule bundle -->
<script type="module" src="./index.tsx"></script>
</body>
</html>
```

{% endsamplefile %}

{% samplefile "src/index.tsx" %}

```tsx
import React from "react";
import { render } from "react-dom";

render(<h1>Hello World</h1>, document.getElementById("root"));
```

{% endsamplefile %}

{% samplefile "package.json" %}

```json
{
"name": "differential-serving-example",
"name": "my-project",
"scripts": {
"start": "parcel serve ./src/index.html",
"build": "parcel build ./src/index.html"
Expand All @@ -196,3 +147,7 @@ render(<h1>Hello World</h1>, document.getElementById("root"));

{% endsamplefile %}
{% endsample %}

## Differential Serving

Parcel also supports differential serving, which means you can serve different bundles to modern browsers and legacy browsers. This results in faster load time for most users as the bundle size will be a lot smaller. Parcel will automatically generate a `<script nomodule>` tag when you use a `<script type="module">` in your HTML, and specify a browserslist that includes targets that do not support ES modules natively. This way, modern browsers will download the smaller `type="module"` version, and legacy browsers will download the `nomodule` version. If all of your browser targets support ES modules natively, or you do not specify a browserslist, then no `nomodule` version will be inserted.
11 changes: 6 additions & 5 deletions src/languages/html.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ HTML assets are often the entry file that you provide to Parcel, but can also be
<img src="./images/header.png" />
More content: <a href="./other.html">Link to another page</a>.

<script src="./index.ts"></script>
<script type="module" src="./index.ts"></script>
</body>
</html>
```
Expand All @@ -33,14 +33,15 @@ HTML assets are often the entry file that you provide to Parcel, but can also be

Parcel detects most references in HTML to other files (such as `<script src="..."`, `<img src="...">`, `<video>` or `<meta property="og:image">`) and processes them as well. These references are rewritten so that they link to the correct output files. Relative filenames are resolved relative to the current HTML file.

One noteworthy aspect of this is that `<script type="module">` automatically creates a ESM JavaScript bundle (and restricting the Browserslist config to browsers supporting ESM). Together with `<script nomodule>`, this makes differential serving very straight forward (see also [Generic Webapp](/getting-started/webapp/#differential-serving)).
Parcel treats `<script>` tags just like the browser does natively. By default, scripts execute in a global environment, and features like `import`, `export`, and `require` are not supported. However, when a `<script type="module">` is used, scripts are treated as modules in their own scope, and can import and export other modules. Features like dynamic `import()`, `new Worker`, and `navigator.serviceWorker.register` are supported in both module and classic scripts. In general, you will want to use `<script type="module">` for modern code, however, for legacy scripts like some older libraries that rely on being executed in a global environment, you can use a script without a `type="module"` attribute.

One noteworthy aspect of this is that `<script type="module">` automatically transpiles to a modern browser target, which will generally be much smaller than transpiling for old browsers. If not all of your browser targets support ES modules natively, then Parcel will also automatically generate a `nomodule` fallback, which will be transpiled to your lowest browser target. See the [Generic Webapp](/getting-started/webapp/#differential-serving) guide for more details.

{% sample %}
{% samplefile "index.html" %}

```html/3,6,7,9
<!DOCTYPE html>
<script nomodule src="./index.ts"></script>
<script type="module" src="./index.ts"></script>
```

Expand All @@ -49,7 +50,7 @@ One noteworthy aspect of this is that `<script type="module">` automatically cre

### Inline script and style tags

`<script>` and `<style>` tags with text content are also processed just like standalone files and the generated bundles are inserted back into the HTML file.
`<script>` and `<style>` tags with text content are also processed just like standalone files and the generated bundles are inserted back into the HTML file. The `type="module"` attribute on script tags works just as described above for external scripts. However, if not all of your browser targets support ES modules natively, Parcel will only compile inline scripts to that target and will not output ESM in order to keep the generated HTML small.

{% sample %}
{% samplefile "index.html" %}
Expand All @@ -59,7 +60,7 @@ One noteworthy aspect of this is that `<script type="module">` automatically cre
<style>
@import "./style.scss";
</style>
<script>
<script type="module">
import value from "./other.ts";
console.log(value);
</script>
Expand Down