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

Expose macros config in babel #2249

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
51 changes: 27 additions & 24 deletions packages/compat/src/babel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
import { join } from 'path';
import type { Transform } from 'babel-plugin-ember-template-compilation';
import type { Options as ResolverTransformOptions } from './resolver-transform';
import MacrosConfig from '@embroider/macros/src/macros-config';
import { buildMacros } from '@embroider/macros/babel';
import type { Options as MacrosOptions } from '@embroider/macros/babel';

export interface CompatBabelState {
plugins: PluginItem[];
Expand All @@ -18,37 +19,39 @@ export interface CompatBabelState {
templateMacros: Transform[];
}

function loadCompatConfig(): CompatBabelState {
interface CompatOptions {
/**
* Options for @embroider/macros
*/
'@embroider/macros': MacrosOptions;
}

function loadCompatConfig(options?: CompatOptions): CompatBabelState {
let compatFile = join(locateEmbroiderWorkingDir(process.cwd()), '_babel_compat_.js');
if (existsSync(compatFile)) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require(compatFile);
}
let macros = MacrosConfig.for({}, process.cwd());
let { plugins: templateMacros, setConfig } = MacrosConfig.transforms();
setConfig(macros);
if (process.env.NODE_ENV === 'development') {
macros.enablePackageDevelopment(process.cwd());
macros.enableRuntimeMode();
}
macros.finalize();

let macros = buildMacros(options?.['@embroider/macros']);

return {
plugins: [],
templateTransforms: [],
babelMacros: macros.babelPluginConfig(),
templateMacros: templateMacros as any,
babelMacros: macros.babelMacros,
templateMacros: macros.templateMacros as any,
};
}

const resolverLoader = new ResolverLoader(process.cwd());

export function pluginsFromV1Addons() {
let config = loadCompatConfig();
export function pluginsFromV1Addons(options?: CompatOptions) {
let config = loadCompatConfig(options);
return config.plugins;
}

export function transformsFromV1Addons() {
let config = loadCompatConfig();
export function transformsFromV1Addons(options?: CompatOptions) {
let config = loadCompatConfig(options);
return config.templateTransforms;
}

Expand All @@ -61,13 +64,13 @@ export function looseModeSupport(): Transform {
return [require.resolve('./resolver-transform'), opts];
}

export function templateMacros() {
let config = loadCompatConfig();
export function templateMacros(options?: CompatOptions) {
let config = loadCompatConfig(options);
return config.templateMacros;
}

export function babelMacros() {
let config = loadCompatConfig();
export function babelMacros(options?: CompatOptions) {
let config = loadCompatConfig(options);
return config.babelMacros;
}

Expand Down Expand Up @@ -150,10 +153,10 @@ export function templateColocation(): PluginItem {
return [templateColocationPluginPath, colocationOptions];
}

export function babelCompatSupport(): PluginItem[] {
return [...babelMacros(), ...oldDebugMacros(), templateColocation(), ...pluginsFromV1Addons()];
export function babelCompatSupport(options?: CompatOptions): PluginItem[] {
return [...babelMacros(options), ...oldDebugMacros(), templateColocation(), ...pluginsFromV1Addons(options)];
}

export function templateCompatSupport(): Transform[] {
return [...transformsFromV1Addons(), ...templateMacros(), looseModeSupport()];
export function templateCompatSupport(options?: CompatOptions): Transform[] {
return [...transformsFromV1Addons(options), ...templateMacros(options), looseModeSupport()];
}
39 changes: 39 additions & 0 deletions packages/macros/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,45 @@ The [Embroider package spec](../../docs/spec.md) proposes fixing this by making

This package works in both Embroider and Classical builds, so that addon authors can switch to this newer pattern without disruption.

## Setting Configuration: from a babel config

1. Add `@embroider/macros` as `devDependency`.
2. In your babel config, do:

```js
const { buildMacros } = require('@embroider/macros/babel');

const macros = buildMacros({
// this is how you configure your own package
setOwnConfig: {
// your config goes here
},
// this is how you can optionally send configuration into your
// dependencies, if those dependencies choose to use
// @embroider/macros configs.
setConfig: {
'some-dependency': {
// config for some-dependency
},
},
});

module.exports = {
plugins: [
// ...
[
"babel-plugin-ember-template-compilation",
{
compilerPath: "ember-source/dist/ember-template-compiler.js",
transforms: [...macros.templateMacros],
},
],
...macros.babelMacros,
],
// ...
};
```

## Setting Configuration: from an Ember app

1. Add `@embroider/macros` as `devDependency`.
Expand Down
5 changes: 5 additions & 0 deletions packages/macros/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"license": "MIT",
"author": "Edward Faulkner",
"main": "src/index.js",
"exports": {
".": "./src/index.js",
"./babel": "./src/babel.js",
"./src/*": "./src/*.js"
},
"files": [
"src/**/*.js",
"src/**/*.d.ts",
Expand Down
83 changes: 83 additions & 0 deletions packages/macros/src/babel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import MacrosConfig from './macros-config';

export interface Options {
/**
* How you configure your own package / app
*/
setOwnConfig?: object;
/**
* This is how you can optionally send configuration into
* your dependencies, if those dependencies choose to use
* @embroider/macros configs.
*
* @example
* ```js
* setConfig: {
* 'some-dependency': {
* // config for some-dependency
* }
* }
* ```
*/
setConfig?: Record<string, object>;

/**
* Callback for further manipulation of the macros' configuration instance.
*
* Useful for libraries to provide their own config with defaults shared between sub-dependencies of those libraries.
*/
configure?: (macrosInstance: MacrosConfig) => void;

/**
* Override the default directory used for the MacrosConfig
*
* defaults to the CWD, via process.cwd()
*/
dir?: string;
}

interface ConfiguredMacros {
/**
* Array of plugins to add to the babel config plugins array
*/
babelMacros: ReturnType<MacrosConfig['babelPluginConfig']>;
/**
* Array of template transforms to pass to the transforms array of the babel-plugin-ember-template-compilation babel plugin
*/
templateMacros: ReturnType<(typeof MacrosConfig)['transforms']>['plugins'];
}

export function buildMacros(options: Options = {}): ConfiguredMacros {
let root = options.dir || process.cwd();
let macros = MacrosConfig.for({}, root);

let transforms = MacrosConfig.transforms();

transforms.setConfig(macros);

let { setOwnConfig, setConfig, configure } = options;

if (setOwnConfig) {
macros.setOwnConfig(root, setOwnConfig);
}

if (setConfig) {
for (let [packageName, config] of Object.entries(setConfig)) {
macros.setConfig(root, packageName, config as object);
}
}

configure?.(macros);

if (process.env.NODE_ENV === 'development') {
macros.enablePackageDevelopment(process.cwd());
macros.enableRuntimeMode();
}

macros.finalize();

return {
babelMacros: macros.babelPluginConfig(),
templateMacros: transforms.plugins,
};
}
11 changes: 7 additions & 4 deletions packages/macros/tests/babel/dependency-satisfies.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { allBabelVersions, runDefault } from '@embroider/test-support';
import { Project } from 'scenario-tester';
import { join } from 'path';
import { MacrosConfig } from '../../src/node';
import { buildMacros } from '../../src/babel';

const ROOT = process.cwd();

Expand All @@ -21,11 +21,14 @@ describe(`dependencySatisfies`, function () {
includePresetsTests: true,
babelConfig() {
project.write();
let config = MacrosConfig.for({}, project.baseDir);
config.finalize();

let config = buildMacros({
dir: project.baseDir,
});

return {
filename: join(project.baseDir, 'sample.js'),
plugins: config.babelPluginConfig(),
plugins: config.babelMacros,
};
},

Expand Down
47 changes: 28 additions & 19 deletions packages/macros/tests/babel/get-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { allBabelVersions } from '@embroider/test-support';
import { makeBabelConfig, allModes, makeRunner } from './helpers';
import { MacrosConfig } from '../../src/node';
import { allModes, makeRunner } from './helpers';
import { dirname } from 'path';
import { buildMacros } from '../../src/babel';

describe(`getConfig`, function () {
let config: MacrosConfig;
let macros: ReturnType<typeof buildMacros>;
let filename: string;
let run: ReturnType<typeof makeRunner>;

allBabelVersions({
babelConfig(version: number) {
let c = makeBabelConfig(version, config);
c.filename = filename;
babelConfig(_version: number) {
let c = {
filename,
presets: [],
plugins: macros.babelMacros,
};
return c;
},
includePresetsTests: true,
Expand All @@ -24,20 +27,26 @@ describe(`getConfig`, function () {
// we know it will be available.
filename = `${dirname(require.resolve('@embroider/core/package.json'))}/sample.js`;

config = MacrosConfig.for({}, dirname(require.resolve('@embroider/core/package.json')));
config.setOwnConfig(filename, {
beverage: 'coffee',
macros = buildMacros({
dir: dirname(require.resolve('@embroider/core/package.json')),
setOwnConfig: {
beverage: 'coffee',
},
setConfig: {
'@babel/core': [1, 2, 3],
'@babel/traverse': {
sizes: [
{ name: 'small', oz: 4 },
{ name: 'medium', oz: 8 },
],
},
},
configure(config) {
config.setGlobalConfig(filename, 'something-very-global', { year: 2020 });
applyMode(config);
},
});
config.setConfig(filename, '@babel/traverse', {
sizes: [
{ name: 'small', oz: 4 },
{ name: 'medium', oz: 8 },
],
});
config.setConfig(filename, '@babel/core', [1, 2, 3]);
config.setGlobalConfig(filename, 'something-very-global', { year: 2020 });
applyMode(config);
config.finalize();

run = makeRunner(transform);
});

Expand Down