diff --git a/packages/babel-plugin-named-asset-import/index.js b/packages/babel-plugin-named-asset-import/index.js index f1989e5ee06..ddf51254b7e 100644 --- a/packages/babel-plugin-named-asset-import/index.js +++ b/packages/babel-plugin-named-asset-import/index.js @@ -5,60 +5,98 @@ const { extname } = require('path'); function namedAssetImportPlugin({ types: t }) { const visited = new WeakSet(); + function generateNewSourcePath(loaderMap, moduleName, sourcePath) { + const ext = extname(sourcePath).substr(1); + const extMap = loaderMap[ext]; + return extMap[moduleName] + ? extMap[moduleName].replace(/\[path\]/, sourcePath) + : sourcePath; + } + + function replaceMatchingSpecifiers(path, loaderMap, callback) { + const sourcePath = path.node.source.value; + const ext = extname(sourcePath).substr(1); + + if (visited.has(path.node) || sourcePath.indexOf('!') !== -1) { + return; + } + + if (loaderMap[ext]) { + path.replaceWithMultiple( + path.node.specifiers.map(specifier => { + const newSpecifier = callback(specifier, sourcePath); + visited.add(newSpecifier); + + return newSpecifier; + }) + ); + } + } + return { visitor: { - ImportDeclaration( + ExportNamedDeclaration( path, { opts: { loaderMap }, } ) { - const sourcePath = path.node.source.value; - const ext = extname(sourcePath).substr(1); - - if (visited.has(path.node) || sourcePath.indexOf('!') !== -1) { + if (!path.node.source) { return; } - if (loaderMap[ext]) { - path.replaceWithMultiple( - path.node.specifiers.map(specifier => { - if (t.isImportDefaultSpecifier(specifier)) { - const newDefaultImport = t.importDeclaration( - [ - t.importDefaultSpecifier( - t.identifier(specifier.local.name) - ), - ], - t.stringLiteral(sourcePath) - ); - - visited.add(newDefaultImport); - return newDefaultImport; - } - - const newImport = t.importDeclaration( - [ - t.importSpecifier( - t.identifier(specifier.local.name), - t.identifier(specifier.imported.name) - ), - ], - t.stringLiteral( - loaderMap[ext][specifier.imported.name] - ? loaderMap[ext][specifier.imported.name].replace( - /\[path\]/, - sourcePath - ) - : sourcePath - ) - ); + replaceMatchingSpecifiers(path, loaderMap, (specifier, sourcePath) => { + if (t.isExportDefaultSpecifier(specifier)) { + return t.exportDeclaration( + [t.exportDefaultSpecifier(t.identifier(specifier.local.name))], + t.stringLiteral(sourcePath) + ); + } - visited.add(newImport); - return newImport; - }) + return t.exportNamedDeclaration( + null, + [ + t.exportSpecifier( + t.identifier(specifier.local.name), + t.identifier(specifier.exported.name) + ), + ], + t.stringLiteral( + generateNewSourcePath(loaderMap, specifier.local.name, sourcePath) + ) ); + }); + }, + ImportDeclaration( + path, + { + opts: { loaderMap }, } + ) { + replaceMatchingSpecifiers(path, loaderMap, (specifier, sourcePath) => { + if (t.isImportDefaultSpecifier(specifier)) { + return t.importDeclaration( + [t.importDefaultSpecifier(t.identifier(specifier.local.name))], + t.stringLiteral(sourcePath) + ); + } + + return t.importDeclaration( + [ + t.importSpecifier( + t.identifier(specifier.local.name), + t.identifier(specifier.imported.name) + ), + ], + t.stringLiteral( + generateNewSourcePath( + loaderMap, + specifier.imported.name, + sourcePath + ) + ) + ); + }); }, }, }; diff --git a/packages/babel-plugin-named-asset-import/index.test.js b/packages/babel-plugin-named-asset-import/index.test.js index 65ad5513e3e..f14139f0fd6 100644 --- a/packages/babel-plugin-named-asset-import/index.test.js +++ b/packages/babel-plugin-named-asset-import/index.test.js @@ -46,5 +46,53 @@ pluginTester({ 'import { logoUrl } from "logo.svg";\n' + 'import { ReactComponent as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";', }, + defaultExport: { + code: 'export default logo;', + output: 'export default logo;', + }, + constExport: { + code: 'export const token = "token";', + output: 'export const token = "token";', + }, + classExport: { + code: 'export class Logo {}', + output: 'export class Logo {}', + }, + namedExport: { + code: 'export { logo } from "logo";', + output: 'export { logo } from "logo";', + }, + namedExportRenamed: { + code: 'export { Url as logo } from "logo";', + output: 'export { Url as logo } from "logo";', + }, + allExport: { + code: 'export * from "logo";', + output: 'export * from "logo";', + }, + svgNamedExport: { + code: 'export { logo } from "logo.svg";', + output: 'export { logo } from "logo.svg";', + }, + svgAllExport: { + code: 'export * from "logo.svg";', + output: 'export * from "logo.svg";', + }, + svgReactComponentNamedExport: { + code: 'export { ReactComponent as Logo } from "logo.svg";', + output: + 'export { ReactComponent as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";', + }, + svgReactComponentExport: { + code: 'export { ReactComponent } from "logo.svg";', + output: + 'export { ReactComponent } from "@svgr/webpack?-prettier,-svgo!logo.svg";', + }, + svgMultipleExport: { + code: 'export { logoUrl , ReactComponent as Logo } from "logo.svg";', + output: + 'export { logoUrl } from "logo.svg";\n' + + 'export { ReactComponent as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";', + }, }, });