diff --git a/src/_utils.js b/src/_utils.js index dcbffeed..91991ad0 100644 --- a/src/_utils.js +++ b/src/_utils.js @@ -190,12 +190,20 @@ export const validateExpression = (expr, scope) => ( expr.traverse(validateExpressionVisitor, scope) ) -export const getExternalReference = (path, imports) => { +export const getExternalReference = (path, {imports, requires}) => { const {node} = path if (!t.isIdentifier(node)) { return null } + const requireExpr = requires.filter(path => ( + path.get('id').node.name === node.name + ))[0] + + if (requireExpr) { + return requireExpr.get('init').get('arguments')[0].node.value + } + const importExpr = imports.filter(path => { const specifiers = path.get('specifiers') if (specifiers.length !== 1) { @@ -230,15 +238,15 @@ export const generateAttribute = (name, value) => ( ) ) -export const isValidCss = (str) => { +export const isValidCss = str => { try { parseCss(str) return true - } catch (e) {} + } catch (err) {} return false } -export const makeSourceMapGenerator = (file) => { +export const makeSourceMapGenerator = file => { const filename = file.opts.sourceFileName const generator = new SourceMapGenerator({ file: filename, diff --git a/src/babel-external.js b/src/babel-external.js index 2954be55..7d2c3d2a 100644 --- a/src/babel-external.js +++ b/src/babel-external.js @@ -6,26 +6,24 @@ import { getExpressionText, restoreExpressions, makeStyledJsxCss, - globalCss, isValidCss, makeSourceMapGenerator, addSourceMaps } from './_utils' -export const exportDefaultDeclarationVisitor = ({ - path: entryPath, +const visitor = ({ + path, styleId, types: t, validate = false, state }) => { - const path = entryPath.get('declaration') if (!path.isTemplateLiteral() || path.isStringLiteral()) { return } const css = getExpressionText(path) const prefix = `[${MARKUP_ATTRIBUTE_EXTERNAL}~="${styleId}"]` - const isTemplateLiteral = css.modified + const isTemplateLiteral = Boolean(css.modified) const useSourceMaps = Boolean(state.file.opts.sourceMaps) let globalCss = css.modified || css @@ -54,7 +52,7 @@ export const exportDefaultDeclarationVisitor = ({ filename ) } else { - localCss = localCss = transform( + localCss = transform( prefix, css.modified || css ) @@ -85,6 +83,20 @@ export const exportDefaultDeclarationVisitor = ({ ) } +export const exportDefaultDeclarationVisitor = ({path, ...rest}) => ( + visitor({ + path: path.get('declaration'), + ...rest + }) +) + +export const moduleExportsVisitor = ({path, ...rest}) => ( + visitor({ + path: path.get('right'), + ...rest + }) +) + export default function ({types}) { return { visitor: { @@ -95,6 +107,17 @@ export default function ({types}) { types, state }) + }, + AssignmentExpression(path, state) { + if (path.get('left').getSource() !== 'module.exports') { + return + } + moduleExportsVisitor({ + path, + styleId: hash(state.file.opts.filename), + types, + state + }) } } } diff --git a/src/babel.js b/src/babel.js index 9a58a0f0..fab1879a 100644 --- a/src/babel.js +++ b/src/babel.js @@ -4,7 +4,10 @@ import hash from 'string-hash' // Ours import transform from '../lib/style-transform' -import {exportDefaultDeclarationVisitor} from './babel-external' +import { + exportDefaultDeclarationVisitor, + moduleExportsVisitor +} from './babel-external' import { isGlobalEl, @@ -34,7 +37,17 @@ export default function ({types: t}) { inherits: jsx, visitor: { ImportDeclaration(path, state) { - state.imports = (state.imports || []).concat(path) + state.imports = (state.imports || []).concat([path]) + }, + VariableDeclarator(path, state) { + const subpath = path.get('init') + if ( + !subpath.isCallExpression() || + subpath.get('callee').node.name !== 'require' + ) { + return + } + state.requires = (state.requires || []).concat([path]) }, JSXOpeningElement(path, state) { const el = path.node @@ -132,7 +145,10 @@ export default function ({types: t}) { const expression = child.get('expression') if (t.isIdentifier(expression)) { - let externalSourcePath = getExternalReference(expression, state.imports) + let externalSourcePath = getExternalReference(expression, { + imports: state.imports, + requires: state.requires + }) if (externalSourcePath) { externalSourcePath = resolvePath(externalSourcePath, state.file.opts.filename) state.externalStyles.push([ @@ -299,6 +315,19 @@ export default function ({types: t}) { validate: true, state }) + }, + AssignmentExpression(path, state) { + if (path.get('left').getSource() !== 'module.exports') { + return + } + const filename = state.file.opts.filename + moduleExportsVisitor({ + path, + styleId: hash(filename), + types: t, + validate: true, + state + }) } } } diff --git a/test/external.js b/test/external.js index c59b5790..1f51581d 100644 --- a/test/external.js +++ b/test/external.js @@ -16,8 +16,14 @@ const transform = (file, opts = {}) => ( test('transpiles external stylesheets', async t => { const {code} = await transform( './fixtures/styles.js', - { sourceMaps: true } + {sourceMaps: true} ) const out = await read('./fixtures/styles.out.js') t.is(code, out.trim()) }) + +test('transpiles external stylesheets (CommonJS modules)', async t => { + const {code} = await transform('./fixtures/styles2.js') + const out = await read('./fixtures/styles2.out.js') + t.is(code, out.trim()) +}) diff --git a/test/fixtures/external-stylesheet.js b/test/fixtures/external-stylesheet.js index 5f4664fd..02bf71bd 100644 --- a/test/fixtures/external-stylesheet.js +++ b/test/fixtures/external-stylesheet.js @@ -1,5 +1,5 @@ import styles from './styles' -import styles2 from './styles2' +const styles2 = require('./styles2') export default () => (
test
diff --git a/test/fixtures/styles2.js b/test/fixtures/styles2.js index 3a6ca0f8..36d75aa2 100644 --- a/test/fixtures/styles2.js +++ b/test/fixtures/styles2.js @@ -1,3 +1,3 @@ -export default ` +module.exports = ` div { font-size: 3em } `