Support for browser native modules has been around for a couple of years now (I first learned about it in the second half of 2016) and you can get rid of webpack and use syntax like import, but since it’s a relatively new thing, But that’s not an excuse not to get to know it, but to experience it.

The first is when browsers started supporting Modules:

  • Safari 10.1
  • Chrome 61
  • Firefox 54 (may need you inabout:configPage Settings Enabledom.moduleScripts.enabled)
  • Edge 16

Data from jakearchibald.com/2017/es-mod…

use

First of all, the only difference is that you need to add a type=”module” attribute to the script tag to indicate that the file is being run as a module.

<script type="module">
  import message from './message.js'

  console.log(message) // hello world
</script>
Copy the code

And then in the corresponding Module file which is often used in WebPack. There is no difference in syntax (webpack is designed to let you use the new syntax in advance 🙂

message.js

export default 'hello world'
Copy the code

Graceful degradation

There is something like a noscript tag. A rollback scheme can be implemented by adding a nomodule attribute to the script tag.

<script type="module">
  import module from './module.js'
</script>
<script nomodule>
  alert('your browsers can not supports es modules! please upgrade it.')
</script>
Copy the code

The nomodule works like this: Browsers that support type=”module” ignore script execution that contains the nomodule attribute. Browsers that do not support type=”module” will ignore the execution of type=”module” scripts. This is because browsers default to parsing only scripts with type=”text/javascript”, and default to text/javascript if the type attribute is not filled in. This means that nomodule scripts are executed when the browser does not support Module.

Some details to pay attention to

After all, it is native to the browser, and there will definitely be some differences in the way webPack is used. (At least one is parsed at runtime and one is compiled locally)

A valid Module path definition

Because it is implemented in the browser, there is no global Module like in Node. So, the path from ‘XXX’ is defined slightly differently from what you’re used to.

// Several paths are supported

import module from 'http://XXX/module.js'
import module from '/XXX/module.js'
import module from './XXX/module.js'
import module from '.. /XXX/module.js'

// Unsupported syntax
import module from 'XXX'
import module from 'XXX/module.js'
Copy the code

In webPack packaged files, referencing global packages is done by importing module from ‘XXX’. This is actually a shorthand that Webpack uses to find the corresponding module in node_modules and import it. But there is no node_modules for natively supported modules. Therefore, when using native Modules, it is important to remember that the path after from must be a valid URL, and that file suffixes must not be omitted (yes, even remote files can be used, unlike Webpack, which requires local files to be bundled together).

The module file defaults to defer

This is another property of script that identifies a file as one that does not block page rendering and executes in document order once the page is loaded.

<script type="module" src="./defer/module.js"></script>
<script src="./defer/simple.js"></script>
<script defer src="./defer/defer.js"></script>
Copy the code

To test the above point, we have introduced three JS files in the page, each of which outputs a string in the order seen in the Console panel:

Inline script also adds the defer feature by default

Because in a normal script, the defer keyword is pointer only to the script file, adding attributes will not take effect if it is inline-script. But in the case of type=”module”, both files and inline scripts will have the feature of defer.

You can add async properties to scripts of module type

Async can be applied to all module type scripts, either inline or file. Adding the async keyword does not mean that the browser will execute the script when it is parsed into the file. Instead, it will wait until all modules on which the script depends have loaded. The convention for import must be declared at the beginning of a piece of code and cannot be declared inside a function

In other words, the order of log output depends entirely on the loading time of module.js.

<script async type="module" >
  import * from './module.js'
  console.log('module')
</script>
<script async src="./defer/async.js"></script>
Copy the code

A Module is loaded only once

The definition of whether this Module is unique is whether the full path corresponding to the resource is consistent. If the current page path to https://www.baidu.com/a/b/c.html, then the file/module. The js,.. /.. / module. Js and https://www.baidu.com/module.js will be considered to be the same module. But module1.js and module1.js in this example? A =1 is considered two modules, so the result of this code execution is that module1.js will be loaded twice.

<script type="module" src="https://blog.jiasm.org/module-usage/example/modules/module1.js"></script>
<script type="module" src="/examples/modules/module1.js"></script>
<script type="module" src="./modules/module1.js"></script>
<script type="module" src="./modules/module1.js? a=1"></script>
<script type="module">
  import * as module1 from './modules/module1.js'
</script>
Copy the code

The online Demo

Some tips on how to use import and export

Whether it’s a native browser version, or a Webpack version. Import and export are basically the same, with little difference in syntax.

Here are some tips that may help you use Modules better.

Rename export

When exporting certain modules, you can also use the as keyword to rename the value you want to export, just like when importing.

// info.js
let name = 'Niko'
let age = 18

export {
  name as firstName,
  age
}

// import
import {firstName, age} from './info.js'
Copy the code

Unlike module.exports = {} in Node, it can be called multiple times and does not override (except for key names).

export { name as firstName }
export { age }
Copy the code

This way both keys are exported.

Export All attributes exported are readable

That is, the attributes exported by export cannot be modified. If you try to modify them, you will get an exception. However, the effect is const if one of the exported values is a reference type, object, array, etc. You can manipulate some properties of the object, such as pushing an array.

export {
  firstName: 'Niko'.packs: [1.2]}Copy the code
import * as results from './export-editable.js'

results.firstName = 'Bellic' // error

results.packs.push(3)        // success
Copy the code

Such a change would affect all references to the module because the same address is used.

The order in which the exports are placed in the code does not affect the final export result

export const name = 'Niko'
export let age = 18

age = 20
Copy the code

Const or let makes no difference to the caller

import {name, age} from './module'

console.log(name, age) // Niko 20
Copy the code

Import Gets several postures for the default module

Default can be obtained in the following ways:

import defaultItem from './import/module.js'
import { default as defaultItem2 } from './import/module.js'
import _, { default as defaultItem3 } from './import/module.js'

console.log(defaultItem === defaultItem2) // true
console.log(defaultItem === defaultItem3) // true
Copy the code

The default rule is that the first alias corresponds to default, but if the first argument is a deconstruction, it will be resolved as a match for all exported items. P.S. having two arguments at the same time means that the first is default and the second is all modules

Export the full syntax as follows:

import * as allThings from './iport/module.js'
Copy the code

Export file similar to index

If you have a requirement like this, and you need ten modules somewhere, importing ten modules at a time is wasteful and visually bad. So you might write a file like index.js, import it into the file, and then use “Import Index”. It might normally read something like this:

import module1 from './module1.js'
import module2 from './module2.js'

export default {
  module1,
  module2
}
Copy the code

Bringing in all modules and exporting them as an Object is really handy. But the index file is still ugly, so you can use the following syntax to do something similar:

export {default as module1} from './module1.js'
export {default as module2} from './module2.js'
Copy the code

Then change it to the following format when calling:

import * as modules from './index.js'
Copy the code

The online Demo

reporter

One of the features mentioned in the recent popular deno is that there is no node_modules, relying on third-party libraries that can be accessed via web requests. However, modules provided natively in browsers are similar implementations, moving in a more flexible direction. May the day come soon when webpack will be abandoned for development 🙂

The resources

  1. es modules in browsers
  2. es6 modules in depth
  3. export – JavaScript | MDN
  4. import – JavaScript | MDN

GitHub repository for the sample code in this article: transport array