Quantcast
Channel: Meteor Blog - Medium
Viewing all articles
Browse latest Browse all 160

Nested Imports in Meteor

$
0
0

A unique feature to Meteor is nested imports. It is undocumented, except for several references in the changelog and a short section in the Meteor 1.4 migration guide. Possibly due to this, it seems to not be well known.

According to the specification, ECMAScript modules only allow import/export at the top level. They can not be placed within any blocks, such as in a function or if block. This means that when the main bundle or dynamic imports are loaded, all modules imported in the bundle would have to be executed right away.

After v8 downloads a js file, it goes through a process of parsing, compiling, then executing it. Other js engines are likely similar. According to the v8 blog post The cost of JavaScript in 2019, they found that Post-download, script execution time is now a dominant cost. This is especially true for mobile devices.

With require, you can delay or avoid executing a module by placing require in a function or if block. The module will be downloaded, parsed, and compiled by the web browser, but execution is delayed until the first time it is required. Meteor, Node, and many bundlers that support commonjs modules do this. However, most bundlers are not able to tree shake modules imported with require, and the ECMAScript specification does not provide a way to do this with import.

ECMAScript modules in Meteor were implemented by Ben Newman with reify. Reify compiles js files to allow using ECMAScript modules within a commonjs environment. Its implementation allows using import statements anywhere in a file. He wrote a document explaining why someone would want to nest imports, along with an ECMAScript Proposal.

Nested imports should not be confused with dynamic imports. Dynamic imports delay downloading a file until it is needed. In contrast, the files imported by nested imports will always be downloaded at the same time as the file with the nested imports. Nested imports reduce execution time, but will not make your client bundle smaller.

// This is a top-level import
// alerts.js is evaluated immediately
import { showAlert } from './alerts.js';

export function reportError() {
// This is a nested import.
// errors.js has already been downloaded, but
// will not be evaluated until the
// first time reportError is called
import sendError from './errors.js';
}

export function showHint () {
// This is a dynamic import.
// hint.js is not downloaded or evaluated until the first time
// showHint is called
import('./hint.js').then(({ showRandomHint }) => {
showRandomHint()
});
}

Since nested imports are not part of the ECMAScript specification, many js parsers do not support them by default.

  • Typescript can not parse them. Typescript files must use require instead to delay an import or make it conditional.
  • The Babel parser has an allowImportExportEverywhere option.
  • Acorn also has an allowImportExportEverywhere option.
  • The default parser in eslint, Espree, does not support nested imports. Instead, you can configure eslint to use Babel as the parser:
{
"parser": "babel-eslint",
"parserOptions": {
"allowImportExportEverywhere": true
}
}

Nested imports have successfully been used by many companies to provide a better experience on mobile for their users. At Monti APM, we halved the execution time of our app code with 3 nested imports. To help you get started with your app, I’ve created a package to identify any imports that could be worth nesting.

Originally published at https://zodern.me.


Nested Imports in Meteor was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.


Viewing all articles
Browse latest Browse all 160

Trending Articles