Skip to content

Commit e18e37a

Browse files
authored
feat: Allow additional identifiers to be passed in to the babel plugin (#966)
* Allow additional identifiers to be passed in to the babel plugin * Now allowing an array of name/package entries to be transformed
1 parent 2d1645d commit e18e37a

File tree

3 files changed

+364
-23
lines changed

3 files changed

+364
-23
lines changed

packages/babel-plugin/src/__snapshots__/index.test.js.snap

Lines changed: 295 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,244 @@ loadable({
586586
});"
587587
`;
588588
589+
exports[`plugin custom signatures named signature should not match default import 1`] = `
590+
"import myLoadable from 'myLoadablePackage';
591+
myLoadable(() => import(\`./ModA\`));"
592+
`;
593+
594+
exports[`plugin custom signatures should match custom default signature 1`] = `
595+
"import myLoadable from 'myLoadablePackage';
596+
myLoadable({
597+
resolved: {},
598+
599+
chunkName() {
600+
return \`ModA\`.replace(/[^a-zA-Z0-9_$()=\\\\-^°]+/g, \\"-\\");
601+
},
602+
603+
isReady(props) {
604+
const key = this.resolve(props);
605+
606+
if (this.resolved[key] !== true) {
607+
return false;
608+
}
609+
610+
if (typeof __webpack_modules__ !== 'undefined') {
611+
return !!__webpack_modules__[key];
612+
}
613+
614+
return false;
615+
},
616+
617+
importAsync: () => import(
618+
/* webpackChunkName: \\"ModA\\" */
619+
\`./ModA\`),
620+
621+
requireAsync(props) {
622+
const key = this.resolve(props);
623+
this.resolved[key] = false;
624+
return this.importAsync(props).then(resolved => {
625+
this.resolved[key] = true;
626+
return resolved;
627+
});
628+
},
629+
630+
requireSync(props) {
631+
const id = this.resolve(props);
632+
633+
if (typeof __webpack_require__ !== 'undefined') {
634+
return __webpack_require__(id);
635+
}
636+
637+
return eval('module.require')(id);
638+
},
639+
640+
resolve() {
641+
if (require.resolveWeak) {
642+
return require.resolveWeak(\`./ModA\`);
643+
}
644+
645+
return eval('require.resolve')(\`./ModA\`);
646+
}
647+
648+
});"
649+
`;
650+
651+
exports[`plugin custom signatures should match custom named signature 1`] = `
652+
"import { myLoadable } from 'myLoadablePackage';
653+
myLoadable({
654+
resolved: {},
655+
656+
chunkName() {
657+
return \`ModA\`.replace(/[^a-zA-Z0-9_$()=\\\\-^°]+/g, \\"-\\");
658+
},
659+
660+
isReady(props) {
661+
const key = this.resolve(props);
662+
663+
if (this.resolved[key] !== true) {
664+
return false;
665+
}
666+
667+
if (typeof __webpack_modules__ !== 'undefined') {
668+
return !!__webpack_modules__[key];
669+
}
670+
671+
return false;
672+
},
673+
674+
importAsync: () => import(
675+
/* webpackChunkName: \\"ModA\\" */
676+
\`./ModA\`),
677+
678+
requireAsync(props) {
679+
const key = this.resolve(props);
680+
this.resolved[key] = false;
681+
return this.importAsync(props).then(resolved => {
682+
this.resolved[key] = true;
683+
return resolved;
684+
});
685+
},
686+
687+
requireSync(props) {
688+
const id = this.resolve(props);
689+
690+
if (typeof __webpack_require__ !== 'undefined') {
691+
return __webpack_require__(id);
692+
}
693+
694+
return eval('module.require')(id);
695+
},
696+
697+
resolve() {
698+
if (require.resolveWeak) {
699+
return require.resolveWeak(\`./ModA\`);
700+
}
701+
702+
return eval('require.resolve')(\`./ModA\`);
703+
}
704+
705+
});"
706+
`;
707+
708+
exports[`plugin custom signatures should match renamed default import 1`] = `
709+
"import renamedLoadable from '@loadable/component';
710+
renamedLoadable({
711+
resolved: {},
712+
713+
chunkName() {
714+
return \`ModA\`.replace(/[^a-zA-Z0-9_$()=\\\\-^°]+/g, \\"-\\");
715+
},
716+
717+
isReady(props) {
718+
const key = this.resolve(props);
719+
720+
if (this.resolved[key] !== true) {
721+
return false;
722+
}
723+
724+
if (typeof __webpack_modules__ !== 'undefined') {
725+
return !!__webpack_modules__[key];
726+
}
727+
728+
return false;
729+
},
730+
731+
importAsync: () => import(
732+
/* webpackChunkName: \\"ModA\\" */
733+
\`./ModA\`),
734+
735+
requireAsync(props) {
736+
const key = this.resolve(props);
737+
this.resolved[key] = false;
738+
return this.importAsync(props).then(resolved => {
739+
this.resolved[key] = true;
740+
return resolved;
741+
});
742+
},
743+
744+
requireSync(props) {
745+
const id = this.resolve(props);
746+
747+
if (typeof __webpack_require__ !== 'undefined') {
748+
return __webpack_require__(id);
749+
}
750+
751+
return eval('module.require')(id);
752+
},
753+
754+
resolve() {
755+
if (require.resolveWeak) {
756+
return require.resolveWeak(\`./ModA\`);
757+
}
758+
759+
return eval('require.resolve')(\`./ModA\`);
760+
}
761+
762+
});"
763+
`;
764+
765+
exports[`plugin custom signatures should match simple default import 1`] = `
766+
"import loadable from '@loadable/component';
767+
loadable({
768+
resolved: {},
769+
770+
chunkName() {
771+
return \`ModA\`.replace(/[^a-zA-Z0-9_$()=\\\\-^°]+/g, \\"-\\");
772+
},
773+
774+
isReady(props) {
775+
const key = this.resolve(props);
776+
777+
if (this.resolved[key] !== true) {
778+
return false;
779+
}
780+
781+
if (typeof __webpack_modules__ !== 'undefined') {
782+
return !!__webpack_modules__[key];
783+
}
784+
785+
return false;
786+
},
787+
788+
importAsync: () => import(
789+
/* webpackChunkName: \\"ModA\\" */
790+
\`./ModA\`),
791+
792+
requireAsync(props) {
793+
const key = this.resolve(props);
794+
this.resolved[key] = false;
795+
return this.importAsync(props).then(resolved => {
796+
this.resolved[key] = true;
797+
return resolved;
798+
});
799+
},
800+
801+
requireSync(props) {
802+
const id = this.resolve(props);
803+
804+
if (typeof __webpack_require__ !== 'undefined') {
805+
return __webpack_require__(id);
806+
}
807+
808+
return eval('module.require')(id);
809+
},
810+
811+
resolve() {
812+
if (require.resolveWeak) {
813+
return require.resolveWeak(\`./ModA\`);
814+
}
815+
816+
return eval('require.resolve')(\`./ModA\`);
817+
}
818+
819+
});"
820+
`;
821+
822+
exports[`plugin custom signatures should not match on undeclared specifiers 1`] = `
823+
"import myLoadable from 'myLoadablePackage';
824+
myLoadable(() => import(\`./ModA\`));"
825+
`;
826+
589827
exports[`plugin loadable.lib should be transpiled too 1`] = `
590828
"import loadable from '@loadable/component';
591829
loadable.lib({
@@ -700,11 +938,6 @@ loadable({
700938
});"
701939
`;
702940
703-
exports[`plugin simple import should not work with renamed specifier by default 1`] = `
704-
"import renamedLoadable from '@loadable/component';
705-
renamedLoadable(() => import(\`./ModA\`));"
706-
`;
707-
708941
exports[`plugin simple import should transform path into "chunk-friendly" name 1`] = `
709942
"import loadable from '@loadable/component';
710943
loadable({
@@ -990,6 +1223,63 @@ renamedLazy({
9901223
});"
9911224
`;
9921225
1226+
exports[`plugin simple import should work with renamed specifier by default 1`] = `
1227+
"import renamedLoadable from '@loadable/component';
1228+
renamedLoadable({
1229+
resolved: {},
1230+
1231+
chunkName() {
1232+
return \`ModA\`.replace(/[^a-zA-Z0-9_$()=\\\\-^°]+/g, \\"-\\");
1233+
},
1234+
1235+
isReady(props) {
1236+
const key = this.resolve(props);
1237+
1238+
if (this.resolved[key] !== true) {
1239+
return false;
1240+
}
1241+
1242+
if (typeof __webpack_modules__ !== 'undefined') {
1243+
return !!__webpack_modules__[key];
1244+
}
1245+
1246+
return false;
1247+
},
1248+
1249+
importAsync: () => import(
1250+
/* webpackChunkName: \\"ModA\\" */
1251+
\`./ModA\`),
1252+
1253+
requireAsync(props) {
1254+
const key = this.resolve(props);
1255+
this.resolved[key] = false;
1256+
return this.importAsync(props).then(resolved => {
1257+
this.resolved[key] = true;
1258+
return resolved;
1259+
});
1260+
},
1261+
1262+
requireSync(props) {
1263+
const id = this.resolve(props);
1264+
1265+
if (typeof __webpack_require__ !== 'undefined') {
1266+
return __webpack_require__(id);
1267+
}
1268+
1269+
return eval('module.require')(id);
1270+
},
1271+
1272+
resolve() {
1273+
if (require.resolveWeak) {
1274+
return require.resolveWeak(\`./ModA\`);
1275+
}
1276+
1277+
return eval('require.resolve')(\`./ModA\`);
1278+
}
1279+
1280+
});"
1281+
`;
1282+
9931283
exports[`plugin simple import should work with template literal 1`] = `
9941284
"import loadable from '@loadable/component';
9951285
loadable({

packages/babel-plugin/src/index.js

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ const properties = [
2020

2121
const LOADABLE_COMMENT = '#__LOADABLE__'
2222

23-
const loadablePlugin = declare((api, { defaultImportSpecifier = 'loadable' }) => {
23+
const loadablePlugin = declare((api, {
24+
signatures = []
25+
}) => {
26+
if (!signatures.find(sig => sig.from == '@loadable/component')) {
27+
signatures.push({name: 'default', from: '@loadable/component'})
28+
}
2429
const { types: t } = api
2530

2631
function collectImportCallPaths(startPath) {
@@ -35,9 +40,9 @@ const loadablePlugin = declare((api, { defaultImportSpecifier = 'loadable' }) =>
3540

3641
const propertyFactories = properties.map(init => init(api))
3742

38-
function isValidIdentifier(path, loadableImportSpecifier, lazyImportSpecifier) {
39-
// `loadable()`
40-
if (loadableImportSpecifier && path.get('callee').isIdentifier({ name: loadableImportSpecifier })) {
43+
function isValidIdentifier(path, loadableImportSpecifiers, lazyImportSpecifier) {
44+
// loadable signatures
45+
if (loadableImportSpecifiers.find(specifier => path.get('callee').isIdentifier({ name: specifier }))) {
4146
return true
4247
}
4348

@@ -48,9 +53,8 @@ const loadablePlugin = declare((api, { defaultImportSpecifier = 'loadable' }) =>
4853

4954
// `loadable.lib()`
5055
return (
51-
loadableImportSpecifier &&
5256
path.get('callee').isMemberExpression() &&
53-
path.get('callee.object').isIdentifier({ name: loadableImportSpecifier }) &&
57+
loadableImportSpecifiers.find(specifier => path.get('callee.object').isIdentifier({ name: specifier })) &&
5458
path.get('callee.property').isIdentifier({ name: 'lib' })
5559
)
5660
}
@@ -119,28 +123,30 @@ const loadablePlugin = declare((api, { defaultImportSpecifier = 'loadable' }) =>
119123
visitor: {
120124
Program: {
121125
enter(programPath) {
122-
let loadableImportSpecifier = defaultImportSpecifier
123126
let lazyImportSpecifier = false
127+
const loadableSpecifiers = []
124128

125129
programPath.traverse({
126130
ImportDefaultSpecifier(path) {
127-
if (!loadableImportSpecifier) {
128-
const { parent } = path
129-
const { local } = path.node
130-
loadableImportSpecifier = parent.source.value == '@loadable/component' &&
131-
local && local.name
131+
const { parent } = path
132+
const { local } = path.node
133+
if (local && signatures.find(signature => signature.name === 'default' && parent.source.value === signature.from)) {
134+
loadableSpecifiers.push(local.name)
132135
}
133136
},
134137
ImportSpecifier(path) {
138+
const { parent } = path
139+
const { imported, local } = path.node
135140
if (!lazyImportSpecifier) {
136-
const { parent } = path
137-
const { imported, local } = path.node
138141
lazyImportSpecifier = parent.source.value == '@loadable/component' &&
139142
imported && imported.name == 'lazy' && local && local.name
140143
}
144+
if (local && imported && signatures.find(signature => imported.name === signature.name && parent.source.value === signature.from)) {
145+
loadableSpecifiers.push(local.name)
146+
}
141147
},
142148
CallExpression(path) {
143-
if (!isValidIdentifier(path, loadableImportSpecifier, lazyImportSpecifier)) return
149+
if (!isValidIdentifier(path, loadableSpecifiers, lazyImportSpecifier)) return
144150
transformImport(path)
145151
},
146152
'ArrowFunctionExpression|FunctionExpression|ObjectMethod': path => {

0 commit comments

Comments
 (0)