Skip to content

Commit

Permalink
fix: globs and webpack resolving (#252)
Browse files Browse the repository at this point in the history
  • Loading branch information
cap-Bernardito committed Sep 16, 2020
1 parent b723d51 commit dd797a2
Show file tree
Hide file tree
Showing 15 changed files with 1,258 additions and 666 deletions.
1,718 changes: 1,080 additions & 638 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"webpack": "^4.0.0 || ^5.0.0"
},
"dependencies": {
"fast-glob": "^3.2.4",
"klona": "^2.0.3",
"loader-utils": "^2.0.0",
"schema-utils": "^2.7.1"
Expand Down
114 changes: 96 additions & 18 deletions src/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,29 @@ import path from 'path';

import Evaluator from 'stylus/lib/visitor/evaluator';

import fastGlob from 'fast-glob';
import { urlToRequest } from 'loader-utils';
import Parser from 'stylus/lib/parser';
import DepsResolver from 'stylus/lib/visitor/deps-resolver';
import nodes from 'stylus/lib/nodes';
import utils from 'stylus/lib/utils';

import { readFile } from './utils';
import { readFile, isDirectory } from './utils';

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

async function resolveFilename(filename, currentDirectory, loaderContext) {
const resolve = loaderContext.getResolve({
conditionNames: ['styl', 'stylus', 'style'],
mainFields: ['styl', 'style', 'stylus', 'main', '...'],
mainFiles: ['index', '...'],
extensions: ['.styl', '.css'],
restrictions: [/\.(css|styl)$/i],
});
async function resolveFilename(
filename,
currentDirectory,
loaderContext,
webpackFileResolver,
webpackGlobResolver,
resolveGlob
) {
const resolve =
typeof resolveGlob === 'undefined'
? webpackFileResolver
: webpackGlobResolver;

const request = urlToRequest(
filename,
Expand Down Expand Up @@ -58,9 +63,9 @@ async function getDependencies(
code,
filepath,
loaderContext,
resolve,
webpackFileResolver,
webpackGlobResolver,
options,
parcelOptions,
seen = new Set()
) {
seen.add(filepath);
Expand All @@ -76,12 +81,57 @@ async function getDependencies(
visitImport(imported) {
const importedPath = imported.path.first.string;

if (!deps.has(importedPath)) {
deps.set(
importedPath,
resolve(importedPath, loaderContext.rootContext, loaderContext)
);
if (!importedPath || deps.has(importedPath)) {
return;
}

if (fastGlob.isDynamicPattern(importedPath)) {
if (
!isDirectory(
loaderContext.fs,
path.join(path.dirname(filepath), importedPath)
)
) {
deps.set(
importedPath,
Promise.resolve().then(async () => {
const [parsedGlob] = fastGlob.generateTasks(importedPath);

parsedGlob.glob =
parsedGlob.base === '.'
? importedPath
: importedPath.slice(parsedGlob.base.length + 1);

const globRoot = await resolveFilename(
parsedGlob.base,
path.dirname(filepath),
loaderContext,
webpackFileResolver,
webpackGlobResolver,
true
);

return {
isGlob: true,
path: path.posix.join(globRoot, parsedGlob.glob),
};
})
);

return;
}
}

deps.set(
importedPath,
resolveFilename(
importedPath,
loaderContext.rootContext,
loaderContext,
webpackFileResolver,
webpackGlobResolver
)
);
}
}

Expand All @@ -93,13 +143,19 @@ async function getDependencies(
await Promise.all(
Array.from(deps.entries()).map(async (result) => {
let [importedPath, resolved] = result;
let pathIsGlob;

try {
resolved = await resolved;
} catch (err) {
resolved = null;
}

if (resolved !== null && resolved.isGlob) {
pathIsGlob = true;
resolved = resolved.path;
}

if (typeof importedPath === 'undefined') {
return;
}
Expand Down Expand Up @@ -131,6 +187,11 @@ async function getDependencies(
}
}

if (pathIsGlob) {
found = await fastGlob(resolved);
found = found.filter((file) => /\.styl$/i.test(file));
}

// Recursively process resolved files as well to get nested deps
for await (const detected of found) {
if (!seen.has(detected)) {
Expand All @@ -146,7 +207,8 @@ async function getDependencies(
source,
detected,
loaderContext,
resolveFilename,
webpackFileResolver,
webpackGlobResolver,
options
)) {
res.set(importPath, resolvedPath);
Expand All @@ -160,6 +222,21 @@ async function getDependencies(
}

export default async function createEvaluator(code, options, loaderContext) {
const webpackFileResolver = loaderContext.getResolve({
conditionNames: ['styl', 'stylus', 'style'],
mainFields: ['styl', 'style', 'stylus', 'main', '...'],
mainFiles: ['index', '...'],
extensions: ['.styl', '.css'],
restrictions: [/\.(css|styl)$/i],
});

const webpackGlobResolver = loaderContext.getResolve({
conditionNames: ['styl', 'stylus', 'style'],
mainFields: ['styl', 'style', 'stylus', 'main', '...'],
mainFiles: ['index', '...'],
resolveToContext: true,
});

let optionsImports = '';

if (options.import) {
Expand All @@ -175,7 +252,8 @@ export default async function createEvaluator(code, options, loaderContext) {
content,
loaderContext.resourcePath,
loaderContext,
resolveFilename,
webpackFileResolver,
webpackGlobResolver,
options
)
)
Expand Down
20 changes: 16 additions & 4 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ function getStylusOptions(loaderContext, loaderOptions) {

function readFile(inputFileSystem, filepath) {
return new Promise((resolve, reject) => {
inputFileSystem.readFile(filepath, (err, stats) => {
if (err) {
reject(err);
inputFileSystem.readFile(filepath, (error, stats) => {
if (error) {
reject(error);
}
resolve(stats);
});
Expand Down Expand Up @@ -95,4 +95,16 @@ function normalizeSourceMap(map, rootContext) {
return newMap;
}

export { getStylusOptions, readFile, normalizeSourceMap };
function isDirectory(inputFileSystem, filePath) {
let stats;

try {
stats = inputFileSystem.statSync(filePath);
} catch (ignoreError) {
return false;
}

return stats.isDirectory();
}

export { getStylusOptions, readFile, normalizeSourceMap, isDirectory };
30 changes: 28 additions & 2 deletions test/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,37 @@ exports[`loader correctly compiles mixin calls inside imported files: errors 1`]

exports[`loader correctly compiles mixin calls inside imported files: warnings 1`] = `Array []`;

exports[`loader imports files listed in glob with webpack import: css 1`] = `
".a-glob {
color: #000;
}
.b-glob {
background: #808080;
}
.glob-in-node {
color: #fff;
}
.glob-in-node {
background: #ff7f50;
}
.index-glob {
font-size: 1rem;
}
.glob-entry {
box-sizing: border-box;
}
"
`;

exports[`loader imports files listed in glob with webpack import: errors 1`] = `Array []`;

exports[`loader imports files listed in glob with webpack import: warnings 1`] = `Array []`;

exports[`loader imports files listed in glob: css 1`] = `
"body {
".a-glob {
color: #000;
}
body {
.b-glob {
background: #808080;
}
"
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/glob/a.styl
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
body
.a-glob
color: black
2 changes: 1 addition & 1 deletion test/fixtures/glob/b.styl
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
body
.b-glob
background: gray
1 change: 0 additions & 1 deletion test/fixtures/glob/index.styl

This file was deleted.

5 changes: 5 additions & 0 deletions test/fixtures/import-glob-webpack.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import '~globAlias/*'
@import '~glob_package/*'

.glob-entry
box-sizing: border-box
1 change: 1 addition & 0 deletions test/fixtures/import-glob.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'glob/*'
2 changes: 2 additions & 0 deletions test/fixtures/node_modules/glob_package/a.styl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions test/fixtures/node_modules/glob_package/b.styl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions test/fixtures/node_modules/glob_package/index.styl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/fixtures/node_modules/glob_package/package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion test/loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ describe('loader', () => {
});

it('imports files listed in glob', async () => {
const testId = './glob/index.styl';
const testId = './import-glob.styl';
const compiler = getCompiler(testId);
const stats = await compile(compiler);
const codeFromBundle = getCodeFromBundle(stats, compiler);
Expand All @@ -470,6 +470,27 @@ describe('loader', () => {
expect(getErrors(stats)).toMatchSnapshot('errors');
});

it('imports files listed in glob with webpack import', async () => {
const testId = './import-glob-webpack.styl';
const compiler = getCompiler(
testId,
{},
{
resolve: {
alias: {
globAlias: path.resolve(__dirname, 'fixtures', 'glob'),
},
},
}
);
const stats = await compile(compiler);
const codeFromBundle = getCodeFromBundle(stats, compiler);

expect(codeFromBundle.css).toMatchSnapshot('css');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
expect(getErrors(stats)).toMatchSnapshot('errors');
});

it('imports files listed in option argument webpack style', async () => {
const testId = './stylus.styl';
const compiler = getCompiler(
Expand Down

0 comments on commit dd797a2

Please sign in to comment.