Skip to content

Commit

Permalink
Fix glob import/require in Stylus assets (#1845)
Browse files Browse the repository at this point in the history
  • Loading branch information
prokopyl authored and DeMoorJasper committed Aug 3, 2018
1 parent 19adf69 commit dd99fa1
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 5 deletions.
58 changes: 53 additions & 5 deletions src/assets/StylusAsset.js
Expand Up @@ -3,7 +3,9 @@ const Asset = require('../Asset');
const localRequire = require('../utils/localRequire');
const Resolver = require('../Resolver');
const fs = require('../utils/fs');
const {dirname} = require('path');
const {dirname, resolve, relative} = require('path');
const isGlob = require('is-glob');
const glob = require('fast-glob');

const URL_RE = /^(?:url\s*\(\s*)?['"]?(?:[#/]|(?:https?:)?\/\/)/i;

Expand Down Expand Up @@ -80,7 +82,25 @@ async function getDependencies(
let path = imported.path.first.string;

if (!deps.has(path)) {
deps.set(path, resolver.resolve(path, filepath));
if (isGlob(path)) {
deps.set(
path,
glob(resolve(dirname(filepath), path), {
onlyFiles: true
}).then(entries =>
Promise.all(
entries.map(entry =>
resolver.resolve(
'./' + relative(dirname(filepath), entry),
filepath
)
)
)
)
);
} else {
deps.set(path, resolver.resolve(path, filepath));
}
}
}
}
Expand All @@ -92,14 +112,17 @@ async function getDependencies(
await Promise.all(
Array.from(deps.entries()).map(async ([path, resolved]) => {
try {
resolved = (await resolved).path;
resolved = await resolved;
resolved = Array.isArray(resolved)
? resolved.map(r => r.path)
: resolved.path;
} catch (err) {
resolved = null;
}

let found;
if (resolved) {
found = [resolved];
found = Array.isArray(resolved) ? resolved : [resolved];
res.set(path, resolved);
} else {
// If we couldn't resolve, try the normal stylus resolver.
Expand Down Expand Up @@ -166,7 +189,18 @@ async function createEvaluator(code, asset, options) {
// This allows stylus files in node_modules to be resolved properly.
// If we find something, update the AST so stylus gets the absolute path to load later.
if (resolved) {
node.string = resolved;
if (!Array.isArray(resolved)) {
node.string = resolved;
} else {
// If the import resolves to multiple files (i.e. glob),
// replace it with a separate import node for each file
return mergeBlocks(
resolved.map(resolvedPath => {
node.string = resolvedPath;
return super.visitImport(imported.clone());
})
);
}
}
}

Expand All @@ -178,4 +212,18 @@ async function createEvaluator(code, asset, options) {
return CustomEvaluator;
}

/**
* Puts the content of all given node blocks into the first one, essentially merging them.
*/
function mergeBlocks(blocks) {
let finalBlock;
for (const block of blocks) {
if (!finalBlock) finalBlock = block;
else {
block.nodes.forEach(node => finalBlock.push(node));
}
}
return finalBlock;
}

module.exports = StylusAsset;
5 changes: 5 additions & 0 deletions test/integration/stylus-glob-import/index.js
@@ -0,0 +1,5 @@
require('./index.styl');

module.exports = function () {
return 2;
};
4 changes: 4 additions & 0 deletions test/integration/stylus-glob-import/index.styl
@@ -0,0 +1,4 @@
@require 'subdir/**/*'

.index
color: red
2 changes: 2 additions & 0 deletions test/integration/stylus-glob-import/subdir/bar/bar.styl
@@ -0,0 +1,2 @@
.bar
color: green
2 changes: 2 additions & 0 deletions test/integration/stylus-glob-import/subdir/foo/foo.styl
@@ -0,0 +1,2 @@
.foo
color: blue
2 changes: 2 additions & 0 deletions test/integration/stylus-glob-import/subdir/main.styl
@@ -0,0 +1,2 @@
.main
color: yellow
31 changes: 31 additions & 0 deletions test/stylus.js
Expand Up @@ -124,4 +124,35 @@ describe('stylus', function() {
let css = await fs.readFile(__dirname + '/dist/index.css', 'utf8');
assert(css.includes('._index_g9mqo_1'));
});

it('should support requiring stylus files with glob dependencies', async function() {
let b = await bundle(
__dirname + '/integration/stylus-glob-import/index.js'
);

await assertBundleTree(b, {
name: 'index.js',
assets: ['index.js', 'index.styl'],
childBundles: [
{
type: 'map'
},
{
name: 'index.css',
assets: ['index.styl'],
childBundles: []
}
]
});

let output = await run(b);
assert.equal(typeof output, 'function');
assert.equal(output(), 2);

let css = await fs.readFile(__dirname + '/dist/index.css', 'utf8');
assert(css.includes('.index'));
assert(css.includes('.main'));
assert(css.includes('.foo'));
assert(css.includes('.bar'));
});
});

0 comments on commit dd99fa1

Please sign in to comment.