diff --git a/src/babel/rewire-imports/__tests__/index.spec.js b/src/babel/rewire-imports/__tests__/index.spec.js index 048156fe2..0870ddf58 100644 --- a/src/babel/rewire-imports/__tests__/index.spec.js +++ b/src/babel/rewire-imports/__tests__/index.spec.js @@ -14,22 +14,6 @@ function transpile(source, pluginOptions = {}, options = {}) { } describe('rewire-imports babel plugin', () => { - it('should throw error if there is a CJS import to linaria', () => { - expect(() => { - transpile(` - const linaria = require('linaria'); - `); - }).toThrowError(); - }); - - it('should not throw error if the CJS import is already rewired', () => { - expect(() => { - transpile(` - const linaria = require('linaria/build/index.runtime.js'); - `); - }).not.toThrowError(); - }); - it('should rewire ESM import to linaria', () => { const { code } = transpile(` import { names } from 'linaria'; @@ -54,4 +38,53 @@ describe('rewire-imports babel plugin', () => { expect(code).toMatch(`require('linaria')`); }); + + it('should rewire CJS require to linaria', () => { + const { code } = transpile(` + const linaria = require('linaria'); + `); + + expect(code).toMatch(`require('linaria/build/index.runtime.js')`); + }); + + it('should rewire CJS require with ternary to linaria', () => { + const { code: consequent } = transpile(` + const linaria = require(dev ? 'linaria' : 'something'); + `); + const { code: alternate } = transpile(` + const linaria = require(dev ? 'something' : 'linaria'); + `); + + expect(consequent).toMatch( + `require(dev ? 'linaria/build/index.runtime.js' : 'something')` + ); + expect(alternate).toMatch( + `require(dev ? 'something' : 'linaria/build/index.runtime.js')` + ); + }); + + it('should do nothing if CJS require is already rewired', () => { + const { code } = transpile(` + const linaria = require('linaria/build/index.runtime.js'); + `); + + expect(code).toMatch(`require('linaria/build/index.runtime.js')`); + }); + + it('should not rewire a member expression require to linaria', () => { + const { code } = transpile(` + const linaria = test.require('linaria'); + `); + + expect(code).toMatch(`test.require('linaria')`); + }); + + it('should skip rewiring if the require is inside prevaled source', () => { + const { code } = transpile(` + /* linaria-preval */ + const linaria = require('linaria'); + `); + + expect(code).toMatch(`require('linaria')`); + }); }); diff --git a/src/babel/rewire-imports/index.js b/src/babel/rewire-imports/index.js index d1c6ffa13..746007942 100644 --- a/src/babel/rewire-imports/index.js +++ b/src/babel/rewire-imports/index.js @@ -1,11 +1,15 @@ /* @flow */ -import type { BabelTypes, NodePath, BabelVariableDeclarator } from '../types'; +import type { BabelTypes, NodePath } from '../types'; type State = { shouldSkip: boolean, }; +function getReplacement(value) { + return `${value}/build/index.runtime.js`.replace(/\/\//g, '/'); +} + function isLinariaImport(value) { try { return require.resolve(value) === require.resolve('linaria'); @@ -27,24 +31,38 @@ export default ({ types }: { types: BabelTypes }) => ({ }, ImportDeclaration(path: NodePath, state: State) { if (!state.shouldSkip && isLinariaImport(path.node.source.value)) { - path.node.source.value = `${path.node.source - .value}/build/index.runtime.js`.replace(/\/\//g, '/'); + path.node.source.value = getReplacement(path.node.source.value); } }, - VariableDeclarator( - path: NodePath>, - state: State - ) { + CallExpression(path: NodePath, state: State) { if ( !state.shouldSkip && - types.isCallExpression(path.node.init) && - path.node.init.callee.name === 'require' && - isLinariaImport(path.node.init.arguments[0].value) + path.node.callee.name === 'require' && + path.node.arguments.length === 1 ) { - // @TODO: it's very tricky to implement this for require - throw path.buildCodeFrameError( - "Linaria's rewire-imports plugin does not support require calls yet" - ); + const argument = path.node.arguments[0]; + + if (types.isStringLiteral(argument)) { + if (isLinariaImport(argument.value)) { + argument.value = getReplacement(argument.value); + } + } else if (types.isConditionalExpression(argument)) { + if ( + types.isStringLiteral(argument.consequent) && + isLinariaImport(argument.consequent.value) + ) { + argument.consequent.value = getReplacement( + argument.consequent.value + ); + } + + if ( + types.isStringLiteral(argument.alternate) && + isLinariaImport(argument.alternate.value) + ) { + argument.alternate.value = getReplacement(argument.alternate.value); + } + } } }, }, diff --git a/src/babel/types.js b/src/babel/types.js index 3787bbc9a..d033f7488 100644 --- a/src/babel/types.js +++ b/src/babel/types.js @@ -64,6 +64,13 @@ export type BabelIdentifier = { type: string, }; +export type BabelConditionalExpression = { + type: string, + test: any, + consequent: any, + alternate: any, +}; + export type BabelJSXExpressionContainer = { type: string, expression: any, @@ -126,6 +133,7 @@ export type BabelTypes = { BabelTaggedTemplateExpression >, isCallExpression: BabelIsTypeFunction, + isConditionalExpression: BabelIsTypeFunction, isIdentifier: BabelIsTypeFunction, isJSXExpressionContainer: BabelIsTypeFunction, isJSXIdentifier: BabelIsTypeFunction, @@ -133,6 +141,7 @@ export type BabelTypes = { isMemberExpression: BabelIsTypeFunction, isObjectExpression: BabelIsTypeFunction, isObjectPattern: BabelIsTypeFunction, + isStringLiteral: BabelIsTypeFunction, isVariableDeclaration: BabelIsTypeFunction, };