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

Create addon-dev package #1001

Merged
merged 4 commits into from
Oct 11, 2021
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
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
/packages/test-setup/**/*.d.ts
/packages/addon-shim/**/*.js
/packages/addon-shim/**/*.d.ts
/packages/addon-dev/**/*.js
/packages/addon-dev/**/*.d.ts
/tests/fixtures/

# unconventional js
Expand Down
7 changes: 7 additions & 0 deletions packages/addon-dev/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# compiled output
/src/**/*.js
/src/**/*.d.ts

# dependencies
/node_modules/

10 changes: 10 additions & 0 deletions packages/addon-dev/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
/src/**/*.js
/src/**/*.d.ts
/src/**/*.map

# dependencies
/node_modules/

5 changes: 5 additions & 0 deletions packages/addon-dev/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
singleQuote: true,
};
34 changes: 34 additions & 0 deletions packages/addon-dev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# @embroider/addon-dev

Utilities for working on v2 addons.

## Rollup Utilities

`@embroider/addon-dev/rollup` exports utilities for building addons with rollup. To use them:

1. Add the following `devDependencies` to your addon:

- @embroider/addon-dev
- rollup
- @babel/core
- @rollup/plugin-babel

2. Copy the `./sample-rollup.config.js` in this repo to your own `rollup.config.js`.

## addon-dev command

The `addon-dev` command helps with common tasks in v2 addons.

- linking up a test application that is embedded within your addon's repo
- synchronizing `devDependencies` from an embedded test application out into
your addon's actual package.json

(You can avoid the need for both of these if you keep your addon and its test app as separate packages in a monorepo instead.)

## Contributing

See the top-level CONTRIBUTING.md in this monorepo.

## License

This project is licensed under the MIT License.
41 changes: 41 additions & 0 deletions packages/addon-dev/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@embroider/addon-dev",
"version": "0.45.0",
"description": "Utilities for addon authors",
"repository": {
"type": "git",
"url": "https://github.com/embroider-build/embroider.git",
"directory": "packages/addon-dev"
},
"license": "MIT",
"author": "Edward Faulkner <edward@eaf4.com>",
"bin": {
"addon-dev": "./src/commands.js"
},
"exports": {
"./template-colocation-plugin": "./src/template-colocation-plugin.js",
"./rollup": "./src/rollup.js"
},
"dependencies": {
"@embroider/shared-internals": "^0.45.0",
"@rollup/pluginutils": "^4.1.1",
"fs-extra": "^10.0.0",
"minimatch": "^3.0.4",
"rollup-plugin-copy-assets": "^2.0.3",
"rollup-plugin-delete": "^2.0.0",
"walk-sync": "^3.0.0",
"yargs": "^17.0.1"
},
"devDependencies": {
"@types/fs-extra": "^9.0.12",
"@types/minimatch": "^3.0.4",
"@types/yargs": "^17.0.3",
"rollup": "^2.58.0"
},
"engines": {
"node": "12.* || 14.* || >= 16"
},
"volta": {
"extends": "../../package.json"
}
}
41 changes: 41 additions & 0 deletions packages/addon-dev/sample-rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import babel from '@rollup/plugin-babel';
import { Addon } from '@embroider/addon-dev/rollup';

const addon = new Addon({
srcDir: 'src',
destDir: 'dist',
});

export default {
// This provides defaults that work well alongside `publicEntrypoints` below.
// You can augment this if you need to.
output: addon.output(),

plugins: [
// These are the modules that users should be able to import from your
// addon. Anything not listed here may get optimized away.
addon.publicEntrypoints(['components/**/*.js', 'index.js']),

// These are the modules that should get reexported into the traditional
// "app" tree. Things in here should also be in publicEntrypoints above, but
// not everything in publicEntrypoints necessarily needs to go here.
addon.appReexports(['components/welcome-page.js']),

// This babel config should *not* apply presets or compile away ES modules.
// It exists only to provide development niceties for you, like automatic
// template colocation.
babel({
plugins: ['@embroider/addon-dev/template-colocation-plugin'],
}),

// Ensure that standalone .hbs files are properly integrated as Javascript.
addon.hbs(),

// addons are allowed to contain imports of .css files, which we want rollup
// to leave alone and keep in the published output.
addon.keepAssets(['**/*.css']),

// Remove leftover build artifacts when starting a new build.
addon.clean(),
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function commonArgs(yargs: Argv) {
}

yargs(process.argv.slice(2))
.scriptName('addon-shim')
.scriptName('addon-dev')
.command(
'link-test-app',
'Ensures that a test app (that lives a subdir under an addon) has access to the addon and all appropriate deps',
Expand Down
31 changes: 31 additions & 0 deletions packages/addon-dev/src/rollup-app-reexports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { readJsonSync, writeJsonSync } from 'fs-extra';
import minimatch from 'minimatch';
import type { Plugin } from 'rollup';

export default function appReexports(opts: {
from: string;
to: string;
include: string[];
}): Plugin {
return {
name: 'app-reexports',
generateBundle(_, bundle) {
let pkg = readJsonSync('package.json');
let appJS: Record<string, string> = {};
for (let filename of Object.keys(bundle)) {
if (opts.include.some((glob) => minimatch(filename, glob))) {
appJS[`./${filename}`] = `./dist/_app_/${filename}`;
this.emitFile({
type: 'asset',
fileName: `_app_/${filename}`,
source: `export { default } from "${pkg.name}/${filename}";\n`,
});
}
}
pkg['ember-addon'] = Object.assign({}, pkg['ember-addon'], {
'app-js': appJS,
});
writeJsonSync('package.json', pkg, { spaces: 2 });
},
};
}
23 changes: 23 additions & 0 deletions packages/addon-dev/src/rollup-hbs-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createFilter } from '@rollup/pluginutils';
import type { Plugin } from 'rollup';
import { readFileSync } from 'fs';
const backtick = '`';

export default function rollupHbsPlugin(): Plugin {
const filter = createFilter('**/*.hbs');

return {
name: 'rollup-hbs-plugin',
load(id: string) {
if (!filter(id)) return;
let input = readFileSync(id, 'utf8');
let code =
`import { hbs } from 'ember-cli-htmlbars';\n` +
`export default hbs${backtick}${input}${backtick};`;
return {
code,
id: id + '.js',
};
},
};
}
48 changes: 48 additions & 0 deletions packages/addon-dev/src/rollup-keep-assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import walkSync from 'walk-sync';
import type { Plugin } from 'rollup';
import { readFileSync } from 'fs';
import { join } from 'path';
import minimatch from 'minimatch';

export default function keepAssets({
from,
include,
}: {
from: string;
include: string[];
}): Plugin {
return {
name: 'copy-assets',

// imports of assets should be left alone in the source code. This can cover
// the case of .css as defined in the embroider v2 addon spec.
async resolveId(source, importer, options) {
const resolution = await this.resolve(source, importer, {
skipSelf: true,
...options,
});
if (
resolution &&
include.some((pattern) => minimatch(resolution.id, pattern))
) {
return { id: source, external: true };
}
return resolution;
},

// the assets go into the output directory in the same relative locations as
// in the input directory
async generateBundle() {
for (let name of walkSync(from, {
globs: include,
directories: false,
})) {
this.emitFile({
type: 'asset',
fileName: name,
source: readFileSync(join(from, name), 'utf8'),
});
}
},
};
}
23 changes: 23 additions & 0 deletions packages/addon-dev/src/rollup-public-entrypoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import walkSync from 'walk-sync';
import type { Plugin } from 'rollup';
import { join } from 'path';

export default function publicEntrypoints(args: {
srcDir: string;
include: string[];
}): Plugin {
return {
name: 'addon-modules',
buildStart() {
for (let name of walkSync(args.srcDir, {
globs: args.include,
})) {
this.emitFile({
type: 'chunk',
id: join(args.srcDir, name),
fileName: name,
});
}
},
};
}
66 changes: 66 additions & 0 deletions packages/addon-dev/src/rollup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { default as hbs } from './rollup-hbs-plugin';
import { default as publicEntrypoints } from './rollup-public-entrypoints';
import { default as appReexports } from './rollup-app-reexports';
import { default as clean } from 'rollup-plugin-delete';
import { default as keepAssets } from './rollup-keep-assets';
import type { Plugin } from 'rollup';

export class Addon {
#srcDir: string;
#destDir: string;

constructor(params: { srcDir?: string; destDir?: string } = {}) {
this.#srcDir = params.srcDir ?? 'src';
this.#destDir = params.destDir ?? 'dist';
}

// Given a list of globs describing modules in your srcDir, this generates
// corresponding appTree modules that contain reexports, and updates your
// package.json metadata to list them all.
appReexports(patterns: string[]): Plugin {
return appReexports({
from: this.#srcDir,
to: this.#destDir,
include: patterns,
});
}

// This configures rollup to emit public entrypoints for each module in your
// srcDir that matches one of the given globs. Typical addons will want to
// match patterns like "components/**/*.js", "index.js", and "test-support.js".
publicEntrypoints(patterns: string[]) {
return publicEntrypoints({ srcDir: this.#srcDir, include: patterns });
}

// This wraps standalone .hbs files as Javascript files using inline
// templates. This means special resolving rules for .hbs files aren't
// required for javascript tooling to understand your package.
hbs() {
return hbs();
}

// By default rollup does not clear the output directory between builds. This
// does that.
clean() {
return clean({ targets: `${this.#destDir}/*` });
}

// V2 Addons are allowed to contain imports of .css files. This tells rollup
// to leave those imports alone and to make sure the corresponding .css files
// are kept in the same relative locations in the destDir as they were in the
// srcDir.
keepAssets(patterns: string[]) {
return keepAssets({
from: this.#srcDir,
include: patterns,
});
}

// This is the default `output` configuration you should pass to rollup. We're
// emitting ES modules, in your `destDir`, and their filenames are equal to
// their bundle names (the bundle names get generated by `publicEntrypoints`
// above).
output() {
return { dir: this.#destDir, format: 'es', entryFileNames: '[name]' };
}
}
4 changes: 4 additions & 0 deletions packages/addon-dev/src/template-colocation-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {
default,
Options,
} from '@embroider/shared-internals/src/template-colocation-plugin';
4 changes: 0 additions & 4 deletions packages/addon-shim/addon-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,4 @@ module.exports = {
.find((a) => a.name === 'ember-auto-import')
.registerV2Addon(this.parent.name, this.parent.pkg.root);
},

includedCommands() {
return require('./src/commands').default;
},
};
9 changes: 1 addition & 8 deletions packages/addon-shim/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,16 @@
"doc": "doc",
"test": "tests"
},
"bin": {
"addon-shim": "./src/commands.js"
},
"scripts": {
"prepare": "tsc"
},
"dependencies": {
"@embroider/shared-internals": "^0.45.0",
"ember-auto-import": "^2.2.0",
"fs-extra": "^10.0.0",
"semver": "^7.3.5",
"yargs": "^17.0.1"
"semver": "^7.3.5"
},
"devDependencies": {
"@types/fs-extra": "^9.0.12",
"@types/semver": "^7.3.6",
"@types/yargs": "^17.0.2",
"typescript": "*",
"webpack": "^5"
},
Expand Down
Loading