Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/embroider-build/ember-auto-import

Zero config import from npm packages
https://github.com/embroider-build/ember-auto-import

Last synced: 13 days ago
JSON representation

Zero config import from npm packages

Awesome Lists containing this project

README

        

# ember-auto-import

Just `import` from NPM, with zero configuration.

## Installation

```
npm install --save-dev ember-auto-import webpack
```

If you're upgrading from 1.x to 2.x [see the upgrade guide](./docs/upgrade-guide-2.0.md).

## Usage

Add whatever dependency you want to your project using NPM or yarn like:

```
npm install --save-dev lodash-es
```

or

```
yarn add --dev lodash-es
```

Then just import it from your Ember app code:

```js
import { capitalize } from 'lodash-es';
```

There is no step two. Works from both app code and test code.

## Dynamic Import

In addition to static top-level `import` statements, you can use dynamic `import()` to lazily load your dependencies. This can be great for reducing your initial bundle size.

Dynamic import is currently a Stage 3 ECMA feature, so to use it there are a few extra setup steps:

1. `npm install --save-dev babel-eslint`
2. In your `.eslintrc.js` file, add

parser: 'babel-eslint'

3. In your `ember-cli-build.js` file, enable the babel plugin provided by ember-auto-import:

```js
let app = new EmberApp(defaults, {
babel: {
plugins: [require.resolve('ember-auto-import/babel-plugin')],
},
});
```

Once you're setup, you can use dynamic `import()` and it will result in loading that particular dependency (and all its recursive dependencies) via a separate Javascript file at runtime. Here's an example of using dynamic import from within a `Route`, so that the extra library needed for the route is loaded at the same time the data is loaded:

```js
export default Route.extend({
model({ id }) {
return Promise.all([
fetch(`/data-for-chart/${id}`).then(response => response.json()),
import('highcharts').then(module => module.default),
]).then(([dataPoints, highcharts]) => {
return { dataPoints, highcharts };
});
},
});
```

If you're using custom deployment code, make sure it will include all the Javascript files in `dist/assets`, not just the default `app.js` and `vendor.js`.

## App imports

`ember-auto-import` was originally designed to allow Ember apps to import from npm packages easily, and would have no influence on your app's files (i.e. files that exist in your `app` folder). This meant that every time you had an import like `import someBigLib from 'my-app-name/lib/massive'` there was no way for you to:

- use webpack plugins to influence the loading of `my-app-name/lib/massive`
- dynamically import `my-app-name/lib/massive` in such a way that it wouldn't increase the size of your asset.
- import assets from your app that would go through webpack loaders

Fortunatly there is a way to configure ember-auto-import to work on certain parts of your app using the `allowAppImports` configuration option. If you set the option to:

```js
let app = new EmberApp(defaults, {
autoImport: {
allowAppImports: [ 'lib/*' ],
}
});
```

Then the `my-app-name/lib/massive` file (and all other files in lib) would now be handled by ember-auto-import. This would then allow you to dynamically `import('my-app-name/lib/massive')` which means that you can dynamically load parts of your app on demand without first splitting them into an addon or an npm package.

## Customizing Build Behavior

While most NPM packages authored in CommonJS or ES Modules will Just Work, for others you may need to give ember-auto-import a hint about what to do.

You can set options like this in your ember-cli-build.js:

```js
// In your ember-cli-build.js file
let app = new EmberApp(defaults, {
autoImport: {
alias: {
// when the app tries to import from "plotly.js", use
// the real package "plotly.js-basic-dist" instead.
'plotly.js': 'plotly.js-basic-dist',

// you can also use aliases to pick a different entrypoint
// within the same package. This can come up when the default
// entrypoint only works in Node, but there is also a browser
// build available (and the author didn't provide a "browser"
// field in package.json that would let us detect it
// automatically).
handlebars: 'handlebars/dist/handlebars',

// We do a prefix match by default, so the above would also
// convert "handlebars/foo" to "handlebars/dist/handlesbars/foo".
// If instad you want an exact match only, you can use a trailing "$".
// For example, this will rewrite "some-package/alpha" to "customized"
// but leave "some-package/beta" alone.
'some-package/alpha$': 'customized',
},
allowAppImports: [
// minimatch patterns for app files that you want to be handled by ember-auto-import
],
exclude: ['some-package'],
skipBabel: [
{
// when an already-babel-transpiled package like "mapbox-gl" is
// not skipped, it can produce errors in the production mode
// due to double transpilation
package: 'mapbox-gl',
semverRange: '*',
},
],
watchDependencies: [
// trigger rebuilds if "some-lib" changes during development
'some-lib',
// trigger rebuilds if "some-lib"'s inner dependency "other-lib" changes
['some-lib', 'other-lib'],
],
webpack: {
// extra webpack configuration goes here
},
},
});
```

Supported Options

- `alias`: _object_, Map from imported names to substitute names that will be imported instead. This is a prefix match by default. To opt out of prefix-matching and only match exactly, add a `$` suffix to the pattern.
- `allowAppImports`: _list of strings, defaults to []_. Files in your app folder that match these minimatch patterns will be handled by ember-auto-import (and thus Webpack) and no longer be part of the regular ember-cli pipeline.
- `exclude`: _list of strings, defaults to []_. Packages in this list will be ignored by ember-auto-import. Can be helpful if the package is already included another way (like a shim from some other Ember addon).
- `forbidEval`: _boolean_, defaults to false. We use `eval` in development by default (because that is the fastest way to provide sourcemaps). If you need to comply with a strict Content Security Policy (CSP), you can set `forbidEval: true`. You will still get sourcemaps, they will just use a slower implementation.
- `insertScriptsAt`: _string_, defaults to undefined. Optionally allows you to take manual control over where ember-auto-import's generated `` tags will be inserted into your HTML and what attributes they will have. See "Customizing HTML Insertion" below.
- `insertStylesAt`: _string_, defaults to undefined. Optionally allows you to take manual control over where ember-auto-import's generated `<link rel="stylesheet">` tags (if any) will be inserted into your HTML and what attributes they will have. See "Customizing HTML Insertion" below.
- `publicAssetURL`: the public URL to your `/assets` directory on the web. Many apps won't need to set this because we try to detect it automatically, but you will need to set this explicitly if you're deploying your assets to a different origin than your app (for example, on a CDN) or if you are using `<script defer>` (which causes scripts to be unable to guess what origin they loaded from).
- `skipBabel`: _list of objects, defaults to []_. The specified packages will be skipped from babel transpilation.
- `watchDependencies`: _list of strings or string arrays, defaults to []_. Tells ember-auto-import that you'd like to trigger a rebuild if one of these auto-imported dependencies changes. Pass a package name that refers to one of your own dependencies, or pass an array of package names to address a deeper dependency.
- `webpack`: _object_, An object that will get merged into the configuration we pass to webpack. This lets you work around quirks in underlying libraries and otherwise customize the way Webpack will assemble your dependencies.

## Usage from Addons

Using ember-auto-import inside an addon is almost exactly the same as inside an app.

### Installing ember-auto-import in an addon

To add ember-auto-import to your addon:

- add ember-auto-import to your `dependencies`, not your `devDependencies`, so it will be present when your addon is used by apps
- add webpack to your `devDependencies` (to support your test suite) but not your `dependencies` (the app's version will be used)
- document for your users that their app must depend on ember-auto-import >= 2 in order to use your addon
- configure ember-auto-import (if needed) in your `index.js` file (not your `ember-cli-build.js` file), like this:

```js
// In your addon's index.js file
module.exports = {
name: 'sample-addon',
options: {
autoImport: {
exclude: ['some-package'],
},
},
};
```

- if your addon uses [Dynamic Import](#dynamic-import), it is [required](https://github.com/babel/ember-cli-babel#options) that you
register the babel plugin in your `index.js` instead of `ember-cli-build.js`:
```js
// index.js
module.exports = {
options: {
babel: {
plugins: [require.resolve('ember-auto-import/babel-plugin')],
},
},
};
```

### Caveats in addons

- ember-auto-import will refuse to import `devDependencies` of your addon into addon code (because that would fail in a consuming application). You _can_ import `devDependencies` into your test suite & dummy app.
- ember-auto-import will not detect import statements inside your `app` folder. This is because the files inside `app` are conceptually not part of your addon's own package namespace at all, so they don't get access to your addon's dependencies. Do all your auto-importing from the `addon` folder, and reexport in `app` as needed.
- while addons are allowed to pass the `autoImport.webpack` option to add things to the webpack config, this makes them less likely to be broadly compatible with apps using different webpack versions. If you need to rely on a specific webpack feature, you should document which versions of webpack you support.

## Customizing HTML Insertion

ember-auto-import uses webpack to generate one or more chunk files containing all your auto-imported dependencies, and then ember-auto-import inserts `<script>` tags to your HTML to make sure those chunks are included into your app (and tests, as appropriate). By default, the "app" webpack chunk(s) will be inserted after Ember's traditional "vendor.js" and the "tests" webpack chunk(s) will be inserted after "test-support.js".

If you need more control over the HTML insertion, you can use the `insertScriptsAt` option (or the `insertStylesAt` option, which is exactly analogous but for standalone CSS instead of JS). To customize HTML insertion:

1. Set `insertScriptsAt` to a custom element name. You get to pick the name so that it can't collide with any existing custom elements in your site, but a good default choice is "auto-import-script":

```js
let app = new EmberApp(defaults, {
autoImport: {
insertScriptsAt: 'auto-import-script',
},
});
```

2. In your `index.html` and `tests/index.html`, use the custom element to designate exactly where you want the "app" and "tests" entrypoints to be inserted:

```diff
<!-- in index.html -->
<body>
{{content-for "body"}}
<script src="{{rootURL}}assets/vendor.js">
+

{{content-for "body-footer"}}

{{content-for "body"}}
{{content-for "test-body"}}








+

+

{{content-for "body-footer"}}
{{content-for "test-body-footer"}}