2018-08-30 14:02:18 +02:00
|
|
|
/**
|
|
|
|
COPYRIGHT (c) 2017-present James Kyle <me@thejameskyle.com>
|
|
|
|
MIT License
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
a copy of this software and associated documentation files (the
|
|
|
|
"Software"), to deal in the Software without restriction, including
|
|
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR
|
|
|
|
*/
|
2018-07-24 11:24:40 +02:00
|
|
|
// This file is https://github.com/jamiebuilds/react-loadable/blob/master/src/babel.js
|
|
|
|
// Modified to also look for `next/dynamic`
|
|
|
|
// Modified to put `webpack` and `modules` under `loadableGenerated` to be backwards compatible with next/dynamic which has a `modules` key
|
|
|
|
// Modified to support `dynamic(import('something'))` and `dynamic(import('something'), options)
|
2018-08-30 14:02:18 +02:00
|
|
|
|
2020-04-22 07:25:43 +02:00
|
|
|
import { NodePath, PluginObj, types as BabelTypes } from '@babel/core'
|
2018-12-02 18:30:00 +01:00
|
|
|
|
2020-05-18 21:24:37 +02:00
|
|
|
export default function ({
|
|
|
|
types: t,
|
|
|
|
}: {
|
|
|
|
types: typeof BabelTypes
|
|
|
|
}): PluginObj {
|
2018-07-24 11:24:40 +02:00
|
|
|
return {
|
|
|
|
visitor: {
|
2019-05-29 13:57:26 +02:00
|
|
|
ImportDeclaration(path: NodePath<BabelTypes.ImportDeclaration>) {
|
2018-07-24 11:24:40 +02:00
|
|
|
let source = path.node.source.value
|
2018-08-30 14:02:18 +02:00
|
|
|
if (source !== 'next/dynamic') return
|
2018-07-24 11:24:40 +02:00
|
|
|
|
2020-05-18 21:24:37 +02:00
|
|
|
let defaultSpecifier = path.get('specifiers').find((specifier) => {
|
2018-07-24 11:24:40 +02:00
|
|
|
return specifier.isImportDefaultSpecifier()
|
|
|
|
})
|
|
|
|
|
|
|
|
if (!defaultSpecifier) return
|
|
|
|
|
2018-12-02 18:30:00 +01:00
|
|
|
const bindingName = defaultSpecifier.node.local.name
|
|
|
|
const binding = path.scope.getBinding(bindingName)
|
|
|
|
|
2018-12-03 14:18:52 +01:00
|
|
|
if (!binding) {
|
2018-12-02 18:30:00 +01:00
|
|
|
return
|
|
|
|
}
|
2018-07-24 11:24:40 +02:00
|
|
|
|
2020-05-18 21:24:37 +02:00
|
|
|
binding.referencePaths.forEach((refPath) => {
|
2018-07-24 11:24:40 +02:00
|
|
|
let callExpression = refPath.parentPath
|
|
|
|
|
|
|
|
if (
|
|
|
|
callExpression.isMemberExpression() &&
|
2018-12-05 21:45:50 +01:00
|
|
|
callExpression.node.computed === false
|
2018-07-24 11:24:40 +02:00
|
|
|
) {
|
2018-12-05 21:45:50 +01:00
|
|
|
const property = callExpression.get('property')
|
2019-05-29 13:57:26 +02:00
|
|
|
if (
|
|
|
|
!Array.isArray(property) &&
|
|
|
|
property.isIdentifier({ name: 'Map' })
|
|
|
|
) {
|
2018-12-05 21:45:50 +01:00
|
|
|
callExpression = callExpression.parentPath
|
|
|
|
}
|
2018-07-24 11:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!callExpression.isCallExpression()) return
|
|
|
|
|
|
|
|
let args = callExpression.get('arguments')
|
2018-12-02 18:30:00 +01:00
|
|
|
if (args.length > 2) {
|
2019-05-29 13:57:26 +02:00
|
|
|
throw callExpression.buildCodeFrameError(
|
|
|
|
'next/dynamic only accepts 2 arguments'
|
|
|
|
)
|
2018-12-02 18:30:00 +01:00
|
|
|
}
|
2018-07-24 11:24:40 +02:00
|
|
|
|
|
|
|
if (!args[0]) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-12-02 18:30:00 +01:00
|
|
|
let loader
|
|
|
|
let options
|
|
|
|
|
2018-09-27 16:40:54 +02:00
|
|
|
if (args[0].isObjectExpression()) {
|
|
|
|
options = args[0]
|
|
|
|
} else {
|
2018-07-24 11:24:40 +02:00
|
|
|
if (!args[1]) {
|
2018-12-02 18:30:00 +01:00
|
|
|
callExpression.node.arguments.push(t.objectExpression([]))
|
2018-07-24 11:24:40 +02:00
|
|
|
}
|
2018-09-27 16:40:54 +02:00
|
|
|
// This is needed as the code is modified above
|
2018-07-24 11:24:40 +02:00
|
|
|
args = callExpression.get('arguments')
|
|
|
|
loader = args[0]
|
|
|
|
options = args[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.isObjectExpression()) return
|
|
|
|
|
|
|
|
let properties = options.get('properties')
|
2019-05-29 13:57:26 +02:00
|
|
|
let propertiesMap: {
|
|
|
|
[key: string]: NodePath<
|
|
|
|
| BabelTypes.ObjectProperty
|
|
|
|
| BabelTypes.ObjectMethod
|
|
|
|
| BabelTypes.SpreadProperty
|
|
|
|
>
|
|
|
|
} = {}
|
2018-07-24 11:24:40 +02:00
|
|
|
|
2020-05-18 21:24:37 +02:00
|
|
|
properties.forEach((property) => {
|
2018-12-02 18:30:00 +01:00
|
|
|
const key: any = property.get('key')
|
2018-07-24 11:24:40 +02:00
|
|
|
propertiesMap[key.node.name] = property
|
|
|
|
})
|
|
|
|
|
|
|
|
if (propertiesMap.loadableGenerated) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (propertiesMap.loader) {
|
|
|
|
loader = propertiesMap.loader.get('value')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (propertiesMap.modules) {
|
|
|
|
loader = propertiesMap.modules.get('value')
|
|
|
|
}
|
|
|
|
|
2018-12-03 14:18:52 +01:00
|
|
|
if (!loader || Array.isArray(loader)) {
|
2018-12-02 18:30:00 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
const dynamicImports: BabelTypes.StringLiteral[] = []
|
2018-07-24 11:24:40 +02:00
|
|
|
|
2018-12-02 18:30:00 +01:00
|
|
|
loader.traverse({
|
2020-06-01 23:00:22 +02:00
|
|
|
Import(importPath) {
|
|
|
|
const importArguments = importPath.parentPath.get('arguments')
|
|
|
|
if (!Array.isArray(importArguments)) return
|
|
|
|
const node: any = importArguments[0].node
|
2018-12-02 18:30:00 +01:00
|
|
|
dynamicImports.push(node)
|
2019-05-29 13:57:26 +02:00
|
|
|
},
|
2018-07-24 11:24:40 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
if (!dynamicImports.length) return
|
2018-12-03 14:18:52 +01:00
|
|
|
|
2019-05-29 13:57:26 +02:00
|
|
|
options.node.properties.push(
|
|
|
|
t.objectProperty(
|
|
|
|
t.identifier('loadableGenerated'),
|
|
|
|
t.objectExpression([
|
|
|
|
t.objectProperty(
|
|
|
|
t.identifier('webpack'),
|
|
|
|
t.arrowFunctionExpression(
|
|
|
|
[],
|
|
|
|
t.arrayExpression(
|
2020-05-18 21:24:37 +02:00
|
|
|
dynamicImports.map((dynamicImport) => {
|
2019-05-29 13:57:26 +02:00
|
|
|
return t.callExpression(
|
|
|
|
t.memberExpression(
|
|
|
|
t.identifier('require'),
|
|
|
|
t.identifier('resolveWeak')
|
|
|
|
),
|
|
|
|
[dynamicImport]
|
|
|
|
)
|
|
|
|
})
|
|
|
|
)
|
2018-07-24 11:24:40 +02:00
|
|
|
)
|
2019-05-29 13:57:26 +02:00
|
|
|
),
|
|
|
|
t.objectProperty(
|
|
|
|
t.identifier('modules'),
|
|
|
|
t.arrayExpression(dynamicImports)
|
|
|
|
),
|
|
|
|
])
|
|
|
|
)
|
|
|
|
)
|
2018-09-25 15:27:09 +02:00
|
|
|
|
|
|
|
// Turns `dynamic(import('something'))` into `dynamic(() => import('something'))` for backwards compat.
|
|
|
|
// This is the replicate the behavior in versions below Next.js 7 where we magically handled not executing the `import()` too.
|
|
|
|
// We'll deprecate this behavior and provide a codemod for it in 7.1.
|
|
|
|
if (loader.isCallExpression()) {
|
|
|
|
const arrowFunction = t.arrowFunctionExpression([], loader.node)
|
|
|
|
loader.replaceWith(arrowFunction)
|
|
|
|
}
|
2018-07-24 11:24:40 +02:00
|
|
|
})
|
2019-05-29 13:57:26 +02:00
|
|
|
},
|
|
|
|
},
|
2018-07-24 11:24:40 +02:00
|
|
|
}
|
|
|
|
}
|