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

Allow injection of whitelisted globals #98

Open
wants to merge 1 commit into
base: master
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
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,20 @@ When you have the same dependency replaced multiple times, there are two behavio

#### Allowing globals (variables) replacement

Currently the library does not enable automatic replacement of globals. To do that, you need to manually "tag" a global for replacement with `di(myGlobal)` in the function scope. For instance:
The library does not enable automatic replacement of all globals. To do that, you either need to need add a `globals` whitelist in babel config:

```js
// In your .babelrc / babel.config.js
// ... other stuff like presets
plugins: [
// ... other plugins
['react-magnetic-di/babel-plugin', {
globals: ['window', 'document', 'fetch'],
}],
],
```

Or manually "tag" a global for replacement with `di(myGlobal)` in the function scope. For instance:

```js
import { di } from 'react-magnetic-di';
Expand All @@ -169,7 +182,7 @@ export async function myApiFetcher() {
}
```

Alternatively, you can create a "getter" so that the library will pick it up:
Alternatively, the recommended approach is to create a "getter" so it becomes explicit:

```js
export const fetchApi = (...args) => fetch(...args);
Expand Down Expand Up @@ -236,7 +249,8 @@ The plugin provides a couple of options to explicitly disable auto injection for
exclude: ['mocks', /test\.tsx?/],
// List of Babel or Node environment names where the plugin should be enabled
enabledEnvs: ['development', 'test'],

// Allow auto injection of some globals by default
globals: ['window', 'document', 'fetch'],
}],
],
```
Expand Down
30 changes: 30 additions & 0 deletions src/babel/__tests__/unit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,36 @@ describe('babel plugin', () => {
`);
});

it('should di globals defined in Babel settings', () => {
const input = `
const useDocument = () => {
return window.document;
};
const useBody = () => {
const window = {};
return () => {
window && document.body;
};
}
`;
const options = { globals: ['window', 'document'] };
expect(babel(input, { options })).toMatchInlineSnapshot(`
"import { di as _di } from "react-magnetic-di";
const useDocument = () => {
const [_window] = _di([window], useDocument);
return _window.document;
};
const useBody = () => {
const [_document] = _di([document], useBody);
const window = {};
return () => {
const [_document2] = _di([_document], null);
window && _document2.body;
};
};"
`);
});

it('should not di component itself class', () => {
const input = `
export default class MyComponent {
Expand Down
16 changes: 14 additions & 2 deletions src/babel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,20 @@ module.exports = function (babel) {
state.addDependency(p)
);

// TODO
// Should we add collection of globals to di via path.scope.globals?
// Collect globals reference paths
if (opts.globals) {
path.traverse({
ReferencedIdentifier(idnt) {
if (
path.scope.globals[idnt.node.name] &&
opts.globals.includes(idnt.node.name) &&
!idnt.scope.hasBinding(idnt)
) {
state.addDependency(idnt);
}
},
});
}

stateCache.set(file, state);
},
Expand Down
3 changes: 2 additions & 1 deletion src/babel/processor-di.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ function processReference(t, path, locationValue, state) {
if (!name || !n.parentPath) return;
// Some babel plugins might rename imports (eg emotion) and references break
// For now we skip, but ideally we would refresh the reference
if (!bodyPath.scope.getBinding(name)) return;
if (!bodyPath.scope.getBinding(name) && !bodyPath.scope.hasGlobal(name))
return;
// Ensure we do not di() self name
if (name === self?.name) {
shadowsOwnName = true;
Expand Down