@parcel/transformer-stylus 2.0.0-nightly.142 → 2.0.0-nightly.1424

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,78 +4,169 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
- var _plugin = require("@parcel/plugin");
9
-
10
- var _utils = require("@parcel/utils");
11
-
12
- var _path = _interopRequireDefault(require("path"));
13
-
7
+ function _plugin() {
8
+ const data = require("@parcel/plugin");
9
+ _plugin = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _utils() {
15
+ const data = require("@parcel/utils");
16
+ _utils = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function _path() {
22
+ const data = _interopRequireDefault(require("path"));
23
+ _path = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
28
+ function _fs() {
29
+ const data = _interopRequireDefault(require("fs"));
30
+ _fs = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ function _stylus() {
36
+ const data = _interopRequireDefault(require("stylus"));
37
+ _stylus = function () {
38
+ return data;
39
+ };
40
+ return data;
41
+ }
42
+ function _parser() {
43
+ const data = _interopRequireDefault(require("stylus/lib/parser"));
44
+ _parser = function () {
45
+ return data;
46
+ };
47
+ return data;
48
+ }
49
+ function _depsResolver() {
50
+ const data = _interopRequireDefault(require("stylus/lib/visitor/deps-resolver"));
51
+ _depsResolver = function () {
52
+ return data;
53
+ };
54
+ return data;
55
+ }
56
+ function _nodes() {
57
+ const data = _interopRequireDefault(require("stylus/lib/nodes"));
58
+ _nodes = function () {
59
+ return data;
60
+ };
61
+ return data;
62
+ }
63
+ function _utils2() {
64
+ const data = _interopRequireDefault(require("stylus/lib/utils"));
65
+ _utils2 = function () {
66
+ return data;
67
+ };
68
+ return data;
69
+ }
70
+ function _evaluator() {
71
+ const data = _interopRequireDefault(require("stylus/lib/visitor/evaluator"));
72
+ _evaluator = function () {
73
+ return data;
74
+ };
75
+ return data;
76
+ }
14
77
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
-
16
78
  const URL_RE = /^(?:url\s*\(\s*)?['"]?(?:[#/]|(?:https?:)?\/\/)/i;
17
-
18
- var _default = new _plugin.Transformer({
19
- getConfig({
20
- asset
79
+ var _default = new (_plugin().Transformer)({
80
+ async loadConfig({
81
+ config
21
82
  }) {
22
- return asset.getConfig(['.stylusrc', '.stylusrc.js'], {
83
+ let configFile = await config.getConfig(['.stylusrc', '.stylusrc.js', '.stylusrc.cjs', '.stylusrc.mjs'], {
23
84
  packageKey: 'stylus'
24
85
  });
86
+ if (configFile) {
87
+ // Resolve relative paths from config file
88
+ if (configFile.contents.paths) {
89
+ configFile.contents.paths = configFile.contents.paths.map(p => _path().default.resolve(_path().default.dirname(configFile.filePath), p));
90
+ }
91
+ return configFile.contents;
92
+ }
25
93
  },
26
-
27
94
  async transform({
28
95
  asset,
29
96
  resolve,
30
97
  config,
31
98
  options
32
99
  }) {
33
- // stylus should be installed locally in the module that's being required
34
- let stylus = await options.packageManager.require('stylus', asset.filePath);
100
+ let stylusConfig = config !== null && config !== void 0 ? config : {};
35
101
  let code = await asset.getCode();
36
- let style = stylus(code, config);
102
+ let style = (0, _stylus().default)(code, {
103
+ ...stylusConfig
104
+ });
37
105
  style.set('filename', asset.filePath);
38
- style.set('include css', true); // Setup a handler for the URL function so we add dependencies for linked assets.
39
-
106
+ style.set('include css', true);
107
+ // Setup a handler for the URL function so we add dependencies for linked assets.
40
108
  style.define('url', node => {
41
- let filename = asset.addURLDependency(node.val, node.filename);
42
- return new stylus.nodes.Literal(`url(${JSON.stringify(filename)})`);
109
+ let filename = asset.addURLDependency(node.val, {
110
+ loc: (0, _utils().createDependencyLocation)({
111
+ line: node.lineno,
112
+ column: node.column
113
+ }, node.val)
114
+ });
115
+ return new (_stylus().default.nodes.Literal)(`url(${JSON.stringify(filename)})`);
43
116
  });
44
- style.set('Evaluator', (await createEvaluator(code, asset, resolve, style.options, options)));
117
+ let {
118
+ resolved: stylusPath
119
+ } = await options.packageManager.resolve('stylus', __filename);
120
+ let nativeGlob = await options.packageManager.require('glob', stylusPath);
121
+ style.set('Evaluator', await createEvaluator(code, asset, resolve, style.options, options, nativeGlob));
45
122
  asset.type = 'css';
46
123
  asset.setCode(style.render());
47
124
  asset.meta.hasDependencies = false;
48
125
  return [asset];
49
126
  }
50
-
51
127
  });
52
-
53
128
  exports.default = _default;
54
-
55
- async function getDependencies(code, filepath, asset, resolve, options, parcelOptions, seen = new Set()) {
129
+ function attemptResolve(importedPath, filepath, asset, resolve, deps) {
130
+ if (deps.has(importedPath)) {
131
+ return;
132
+ }
133
+ if ((0, _utils().isGlob)(importedPath)) {
134
+ // Invalidate when new files are created that match the glob pattern.
135
+ let absoluteGlob = _path().default.resolve(_path().default.dirname(filepath), importedPath);
136
+ asset.invalidateOnFileCreate({
137
+ glob: absoluteGlob
138
+ });
139
+ deps.set(importedPath, (0, _utils().glob)(absoluteGlob, asset.fs, {
140
+ onlyFiles: true
141
+ }).then(entries => Promise.all(entries.map(entry => resolve(filepath, './' + _path().default.relative(_path().default.dirname(filepath), entry), {
142
+ packageConditions: ['stylus', 'style']
143
+ })))));
144
+ } else {
145
+ deps.set(importedPath, resolve(filepath, importedPath, {
146
+ packageConditions: ['stylus', 'style']
147
+ }));
148
+ }
149
+ }
150
+ async function getDependencies(code, filepath, asset, resolve, options, parcelOptions, nativeGlob, seen = new Set(), includeImports = true) {
56
151
  seen.add(filepath);
57
- const [Parser, DepsResolver, nodes, utils] = await Promise.all(['parser', 'visitor/deps-resolver', 'nodes', 'utils'].map(dep => parcelOptions.packageManager.require('stylus/lib/' + dep, filepath)));
58
- nodes.filename = asset.filePath;
59
- let parser = new Parser(code, options);
152
+ _nodes().default.filename = asset.filePath;
153
+ let parser = new (_parser().default)(code, options);
60
154
  let ast = parser.parse();
61
155
  let deps = new Map();
62
- new class extends DepsResolver {
156
+ if (includeImports && options.imports) {
157
+ for (let importedPath of options.imports) {
158
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
159
+ }
160
+ }
161
+ class ImportVisitor extends _depsResolver().default {
63
162
  visitImport(imported) {
64
163
  let importedPath = imported.path.first.string;
65
-
66
- if (!deps.has(importedPath)) {
67
- if ((0, _utils.isGlob)(importedPath)) {
68
- deps.set(importedPath, (0, _utils.glob)(_path.default.resolve(_path.default.dirname(filepath), importedPath), parcelOptions.inputFS, {
69
- onlyFiles: true
70
- }).then(entries => Promise.all(entries.map(entry => resolve(filepath, './' + _path.default.relative(_path.default.dirname(filepath), entry))))));
71
- } else {
72
- deps.set(importedPath, resolve(filepath, importedPath));
73
- }
74
- }
164
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
75
165
  }
166
+ }
167
+ new ImportVisitor(ast, options).visit(ast);
76
168
 
77
- }(ast, options).visit(ast); // Recursively process depdendencies, and return a map with all resolved paths.
78
-
169
+ // Recursively process depdendencies, and return a map with all resolved paths.
79
170
  let res = new Map();
80
171
  await Promise.all(Array.from(deps.entries()).map(async ([importedPath, resolved]) => {
81
172
  try {
@@ -83,43 +174,42 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
83
174
  } catch (err) {
84
175
  resolved = null;
85
176
  }
86
-
87
177
  let found;
88
-
89
- if (resolved) {
178
+ if (resolved && (!Array.isArray(resolved) || resolved.length > 0)) {
90
179
  found = Array.isArray(resolved) ? resolved : [resolved];
91
180
  res.set(importedPath, resolved);
92
181
  } else {
93
182
  // If we couldn't resolve, try the normal stylus resolver.
94
183
  // We just need to do this to keep track of the dependencies - stylus does the real work.
184
+
95
185
  // support optional .styl
96
186
  let originalPath = importedPath;
97
-
98
187
  if (!/\.styl$/i.test(importedPath)) {
99
188
  importedPath += '.styl';
100
189
  }
101
190
 
102
- let paths = (options.paths || []).concat(_path.default.dirname(filepath || '.'));
103
- found = utils.find(importedPath, paths, filepath);
104
-
191
+ // Patch the native FS so we use Parcel's FS, and track files that are
192
+ // checked so we invalidate the cache when they are created.
193
+ let restore = patchNativeFS(asset.fs, nativeGlob);
194
+ let paths = [...new Set((options.paths || []).concat(_path().default.dirname(filepath || '.')))];
195
+ found = _utils2().default.find(importedPath, paths, filepath);
105
196
  if (!found) {
106
- found = utils.lookupIndex(originalPath, paths, filepath);
197
+ found = _utils2().default.lookupIndex(originalPath, paths, filepath);
198
+ }
199
+ for (let invalidation of restore()) {
200
+ asset.invalidateOnFileCreate(invalidation);
107
201
  }
108
-
109
202
  if (!found) {
110
203
  throw new Error('failed to locate file ' + originalPath);
111
204
  }
112
- } // Recursively process resolved files as well to get nested deps
113
-
205
+ }
114
206
 
207
+ // Recursively process resolved files as well to get nested deps
115
208
  for (let resolved of found) {
116
209
  if (!seen.has(resolved)) {
117
- await asset.addIncludedFile({
118
- filePath: resolved
119
- });
210
+ await asset.invalidateOnFileChange(resolved);
120
211
  let code = await asset.fs.readFile(resolved, 'utf8');
121
-
122
- for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, seen)) {
212
+ for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, nativeGlob, seen, false)) {
123
213
  res.set(path, resolvedPath);
124
214
  }
125
215
  }
@@ -127,23 +217,22 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
127
217
  }));
128
218
  return res;
129
219
  }
220
+ async function createEvaluator(code, asset, resolve, options, parcelOptions, nativeGlob) {
221
+ const deps = await getDependencies(code, asset.filePath, asset, resolve, options, parcelOptions, nativeGlob);
130
222
 
131
- async function createEvaluator(code, asset, resolve, options, parcelOptions) {
132
- const deps = await getDependencies(code, asset.filePath, asset, resolve, options, parcelOptions);
133
- const Evaluator = await parcelOptions.packageManager.require('stylus/lib/visitor/evaluator', asset.filePath); // This is a custom stylus evaluator that extends stylus with support for the node
223
+ // This is a custom stylus evaluator that extends stylus with support for the node
134
224
  // require resolution algorithm. It also adds all dependencies to the parcel asset
135
225
  // tree so the file watcher works correctly, etc.
136
-
137
- return class extends Evaluator {
226
+ class CustomEvaluator extends _evaluator().default {
138
227
  visitImport(imported) {
139
228
  let node = this.visit(imported.path).first;
140
229
  let path = node.string;
141
-
142
230
  if (node.name !== 'url' && path && !URL_RE.test(path)) {
143
- let resolved = deps.get(path); // First try resolving using the node require resolution algorithm.
231
+ let resolved = deps.get(path);
232
+
233
+ // First try resolving using the node require resolution algorithm.
144
234
  // This allows stylus files in node_modules to be resolved properly.
145
235
  // If we find something, update the AST so stylus gets the absolute path to load later.
146
-
147
236
  if (resolved) {
148
237
  if (!Array.isArray(resolved)) {
149
238
  node.string = resolved;
@@ -152,26 +241,85 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
152
241
  // replace it with a separate import node for each file
153
242
  return mergeBlocks(resolved.map(resolvedPath => {
154
243
  node.string = resolvedPath;
155
- return super.visitImport(imported.clone());
244
+ let restore = patchNativeFS(asset.fs, nativeGlob);
245
+ let res = super.visitImport(imported.clone());
246
+ restore();
247
+ return res;
156
248
  }));
157
249
  }
158
250
  }
159
- } // Done. Let stylus do its thing.
251
+ }
160
252
 
253
+ // Patch the native FS so stylus uses Parcel's FS to read the file.
254
+ let restore = patchNativeFS(asset.fs, nativeGlob);
161
255
 
162
- return super.visitImport(imported);
256
+ // Done. Let stylus do its thing.
257
+ let res = super.visitImport(imported);
258
+ restore();
259
+ return res;
163
260
  }
261
+ }
262
+ return CustomEvaluator;
263
+ }
264
+ function patchNativeFS(fs, nativeGlob) {
265
+ let invalidations = [];
266
+ let readFileSync = _fs().default.readFileSync;
267
+ let statSync = _fs().default.statSync;
268
+
269
+ // $FlowFixMe
270
+ _fs().default.readFileSync = (filename, encoding) => {
271
+ return fs.readFileSync(filename, encoding);
272
+ };
273
+
274
+ // $FlowFixMe
275
+ _fs().default.statSync = p => {
276
+ try {
277
+ return fs.statSync(p);
278
+ } catch (err) {
279
+ // Track files that were checked but don't exist so that we watch for their creation.
280
+ if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
281
+ invalidations.push({
282
+ filePath: p
283
+ });
284
+ }
285
+ throw err;
286
+ }
287
+ };
164
288
 
289
+ // Patch the `glob` module as well so we use the Parcel FS and track invalidations.
290
+ let glob = nativeGlob.sync;
291
+ nativeGlob.sync = p => {
292
+ let res = (0, _utils().globSync)(p, fs);
293
+ if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
294
+ // Sometimes stylus passes file paths with no glob parts to the `glob` module.
295
+ // We want to avoid treating these as globs for performance.
296
+ if ((0, _utils().isGlob)(p)) {
297
+ invalidations.push({
298
+ glob: p
299
+ });
300
+ } else if (res.length === 0) {
301
+ invalidations.push({
302
+ filePath: p
303
+ });
304
+ }
305
+ }
306
+ return res;
307
+ };
308
+ return () => {
309
+ // $FlowFixMe
310
+ _fs().default.readFileSync = readFileSync;
311
+ // $FlowFixMe
312
+ _fs().default.statSync = statSync;
313
+ nativeGlob.sync = glob;
314
+ return invalidations;
165
315
  };
166
316
  }
317
+
167
318
  /**
168
319
  * Puts the content of all given node blocks into the first one, essentially merging them.
169
320
  */
170
-
171
-
172
321
  function mergeBlocks(blocks) {
173
322
  let finalBlock;
174
-
175
323
  for (const block of blocks) {
176
324
  if (finalBlock) {
177
325
  // $FlowFixMe - finalBlock is definitely defined
@@ -180,6 +328,5 @@ function mergeBlocks(blocks) {
180
328
  finalBlock = block;
181
329
  }
182
330
  }
183
-
184
331
  return finalBlock;
185
332
  }
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "@parcel/transformer-stylus",
3
- "version": "2.0.0-nightly.142+c87c29dd",
3
+ "version": "2.0.0-nightly.1424+eeb3ba3de",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
+ "funding": {
9
+ "type": "opencollective",
10
+ "url": "https://opencollective.com/parcel"
11
+ },
8
12
  "repository": {
9
13
  "type": "git",
10
14
  "url": "https://github.com/parcel-bundler/parcel.git"
@@ -12,15 +16,13 @@
12
16
  "main": "lib/StylusTransformer.js",
13
17
  "source": "src/StylusTransformer.js",
14
18
  "engines": {
15
- "node": ">= 10.0.0",
16
- "parcel": "^2.0.0-alpha.1.1"
19
+ "node": ">= 12.0.0",
20
+ "parcel": "2.0.0-nightly.1422+eeb3ba3de"
17
21
  },
18
22
  "dependencies": {
19
- "@parcel/plugin": "2.0.0-nightly.142+c87c29dd",
20
- "@parcel/utils": "2.0.0-nightly.142+c87c29dd"
21
- },
22
- "devDependencies": {
23
- "stylus": "^0.54.5"
23
+ "@parcel/plugin": "2.0.0-nightly.1424+eeb3ba3de",
24
+ "@parcel/utils": "2.0.0-nightly.1424+eeb3ba3de",
25
+ "stylus": "^0.55.0"
24
26
  },
25
- "gitHead": "c87c29dd9ca09832e9677bb4d914d2e64bb2d5b8"
27
+ "gitHead": "eeb3ba3de6e4fe037cd4f5d73939fa6867faa1f4"
26
28
  }
@@ -1,34 +1,72 @@
1
1
  // @flow
2
2
 
3
3
  import {Transformer} from '@parcel/plugin';
4
- import {isGlob, glob} from '@parcel/utils';
4
+ import {createDependencyLocation, isGlob, glob, globSync} from '@parcel/utils';
5
5
  import path from 'path';
6
+ import nativeFS from 'fs';
7
+ import stylus from 'stylus';
8
+ import Parser from 'stylus/lib/parser';
9
+ import DepsResolver from 'stylus/lib/visitor/deps-resolver';
10
+ import nodes from 'stylus/lib/nodes';
11
+ import utils from 'stylus/lib/utils';
12
+ import Evaluator from 'stylus/lib/visitor/evaluator';
6
13
 
7
14
  const URL_RE = /^(?:url\s*\(\s*)?['"]?(?:[#/]|(?:https?:)?\/\/)/i;
8
15
 
9
- export default new Transformer({
10
- getConfig({asset}) {
11
- return asset.getConfig(['.stylusrc', '.stylusrc.js'], {
12
- packageKey: 'stylus',
13
- });
16
+ export default (new Transformer({
17
+ async loadConfig({config}) {
18
+ let configFile = await config.getConfig(
19
+ ['.stylusrc', '.stylusrc.js', '.stylusrc.cjs', '.stylusrc.mjs'],
20
+ {
21
+ packageKey: 'stylus',
22
+ },
23
+ );
24
+
25
+ if (configFile) {
26
+ // Resolve relative paths from config file
27
+ if (configFile.contents.paths) {
28
+ configFile.contents.paths = configFile.contents.paths.map(p =>
29
+ path.resolve(path.dirname(configFile.filePath), p),
30
+ );
31
+ }
32
+
33
+ return configFile.contents;
34
+ }
14
35
  },
15
36
 
16
37
  async transform({asset, resolve, config, options}) {
17
- // stylus should be installed locally in the module that's being required
18
- let stylus = await options.packageManager.require('stylus', asset.filePath);
19
-
38
+ let stylusConfig = config ?? {};
20
39
  let code = await asset.getCode();
21
- let style = stylus(code, config);
40
+ let style = stylus(code, {...stylusConfig});
22
41
  style.set('filename', asset.filePath);
23
42
  style.set('include css', true);
24
43
  // Setup a handler for the URL function so we add dependencies for linked assets.
25
- style.define('url', node => {
26
- let filename = asset.addURLDependency(node.val, node.filename);
44
+ style.define('url', (node: stylus.nodes.String | stylus.nodes.Literal) => {
45
+ let filename = asset.addURLDependency(node.val, {
46
+ loc: createDependencyLocation(
47
+ {line: node.lineno, column: node.column},
48
+ node.val,
49
+ ),
50
+ });
27
51
  return new stylus.nodes.Literal(`url(${JSON.stringify(filename)})`);
28
52
  });
53
+
54
+ let {resolved: stylusPath} = await options.packageManager.resolve(
55
+ 'stylus',
56
+ __filename,
57
+ );
58
+ let nativeGlob = await options.packageManager.require('glob', stylusPath);
59
+
29
60
  style.set(
30
61
  'Evaluator',
31
- await createEvaluator(code, asset, resolve, style.options, options),
62
+ await createEvaluator(
63
+ code,
64
+ asset,
65
+ resolve,
66
+ style.options,
67
+ options,
68
+ nativeGlob,
69
+ ),
32
70
  );
33
71
 
34
72
  asset.type = 'css';
@@ -36,7 +74,45 @@ export default new Transformer({
36
74
  asset.meta.hasDependencies = false;
37
75
  return [asset];
38
76
  },
39
- });
77
+ }): Transformer);
78
+
79
+ function attemptResolve(importedPath, filepath, asset, resolve, deps) {
80
+ if (deps.has(importedPath)) {
81
+ return;
82
+ }
83
+
84
+ if (isGlob(importedPath)) {
85
+ // Invalidate when new files are created that match the glob pattern.
86
+ let absoluteGlob = path.resolve(path.dirname(filepath), importedPath);
87
+ asset.invalidateOnFileCreate({glob: absoluteGlob});
88
+
89
+ deps.set(
90
+ importedPath,
91
+ glob(absoluteGlob, asset.fs, {
92
+ onlyFiles: true,
93
+ }).then(entries =>
94
+ Promise.all(
95
+ entries.map(entry =>
96
+ resolve(
97
+ filepath,
98
+ './' + path.relative(path.dirname(filepath), entry),
99
+ {
100
+ packageConditions: ['stylus', 'style'],
101
+ },
102
+ ),
103
+ ),
104
+ ),
105
+ ),
106
+ );
107
+ } else {
108
+ deps.set(
109
+ importedPath,
110
+ resolve(filepath, importedPath, {
111
+ packageConditions: ['stylus', 'style'],
112
+ }),
113
+ );
114
+ }
115
+ }
40
116
 
41
117
  async function getDependencies(
42
118
  code,
@@ -45,14 +121,11 @@ async function getDependencies(
45
121
  resolve,
46
122
  options,
47
123
  parcelOptions,
124
+ nativeGlob,
48
125
  seen = new Set(),
126
+ includeImports = true,
49
127
  ) {
50
128
  seen.add(filepath);
51
- const [Parser, DepsResolver, nodes, utils] = await Promise.all(
52
- ['parser', 'visitor/deps-resolver', 'nodes', 'utils'].map(dep =>
53
- parcelOptions.packageManager.require('stylus/lib/' + dep, filepath),
54
- ),
55
- );
56
129
 
57
130
  nodes.filename = asset.filePath;
58
131
 
@@ -60,35 +133,16 @@ async function getDependencies(
60
133
  let ast = parser.parse();
61
134
  let deps = new Map();
62
135
 
136
+ if (includeImports && options.imports) {
137
+ for (let importedPath of options.imports) {
138
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
139
+ }
140
+ }
141
+
63
142
  class ImportVisitor extends DepsResolver {
64
143
  visitImport(imported) {
65
144
  let importedPath = imported.path.first.string;
66
-
67
- if (!deps.has(importedPath)) {
68
- if (isGlob(importedPath)) {
69
- deps.set(
70
- importedPath,
71
- glob(
72
- path.resolve(path.dirname(filepath), importedPath),
73
- parcelOptions.inputFS,
74
- {
75
- onlyFiles: true,
76
- },
77
- ).then(entries =>
78
- Promise.all(
79
- entries.map(entry =>
80
- resolve(
81
- filepath,
82
- './' + path.relative(path.dirname(filepath), entry),
83
- ),
84
- ),
85
- ),
86
- ),
87
- );
88
- } else {
89
- deps.set(importedPath, resolve(filepath, importedPath));
90
- }
91
- }
145
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
92
146
  }
93
147
  }
94
148
 
@@ -105,7 +159,7 @@ async function getDependencies(
105
159
  }
106
160
 
107
161
  let found;
108
- if (resolved) {
162
+ if (resolved && (!Array.isArray(resolved) || resolved.length > 0)) {
109
163
  found = Array.isArray(resolved) ? resolved : [resolved];
110
164
  res.set(importedPath, resolved);
111
165
  } else {
@@ -118,12 +172,24 @@ async function getDependencies(
118
172
  importedPath += '.styl';
119
173
  }
120
174
 
121
- let paths = (options.paths || []).concat(path.dirname(filepath || '.'));
175
+ // Patch the native FS so we use Parcel's FS, and track files that are
176
+ // checked so we invalidate the cache when they are created.
177
+ let restore = patchNativeFS(asset.fs, nativeGlob);
178
+
179
+ let paths = [
180
+ ...new Set(
181
+ (options.paths || []).concat(path.dirname(filepath || '.')),
182
+ ),
183
+ ];
122
184
  found = utils.find(importedPath, paths, filepath);
123
185
  if (!found) {
124
186
  found = utils.lookupIndex(originalPath, paths, filepath);
125
187
  }
126
188
 
189
+ for (let invalidation of restore()) {
190
+ asset.invalidateOnFileCreate(invalidation);
191
+ }
192
+
127
193
  if (!found) {
128
194
  throw new Error('failed to locate file ' + originalPath);
129
195
  }
@@ -132,7 +198,7 @@ async function getDependencies(
132
198
  // Recursively process resolved files as well to get nested deps
133
199
  for (let resolved of found) {
134
200
  if (!seen.has(resolved)) {
135
- await asset.addIncludedFile({filePath: resolved});
201
+ await asset.invalidateOnFileChange(resolved);
136
202
 
137
203
  let code = await asset.fs.readFile(resolved, 'utf8');
138
204
  for (let [path, resolvedPath] of await getDependencies(
@@ -142,7 +208,9 @@ async function getDependencies(
142
208
  resolve,
143
209
  options,
144
210
  parcelOptions,
211
+ nativeGlob,
145
212
  seen,
213
+ false,
146
214
  )) {
147
215
  res.set(path, resolvedPath);
148
216
  }
@@ -154,7 +222,14 @@ async function getDependencies(
154
222
  return res;
155
223
  }
156
224
 
157
- async function createEvaluator(code, asset, resolve, options, parcelOptions) {
225
+ async function createEvaluator(
226
+ code,
227
+ asset,
228
+ resolve,
229
+ options,
230
+ parcelOptions,
231
+ nativeGlob,
232
+ ) {
158
233
  const deps = await getDependencies(
159
234
  code,
160
235
  asset.filePath,
@@ -162,10 +237,7 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
162
237
  resolve,
163
238
  options,
164
239
  parcelOptions,
165
- );
166
- const Evaluator = await parcelOptions.packageManager.require(
167
- 'stylus/lib/visitor/evaluator',
168
- asset.filePath,
240
+ nativeGlob,
169
241
  );
170
242
 
171
243
  // This is a custom stylus evaluator that extends stylus with support for the node
@@ -190,21 +262,79 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
190
262
  return mergeBlocks(
191
263
  resolved.map(resolvedPath => {
192
264
  node.string = resolvedPath;
193
- return super.visitImport(imported.clone());
265
+ let restore = patchNativeFS(asset.fs, nativeGlob);
266
+ let res = super.visitImport(imported.clone());
267
+ restore();
268
+ return res;
194
269
  }),
195
270
  );
196
271
  }
197
272
  }
198
273
  }
199
274
 
275
+ // Patch the native FS so stylus uses Parcel's FS to read the file.
276
+ let restore = patchNativeFS(asset.fs, nativeGlob);
277
+
200
278
  // Done. Let stylus do its thing.
201
- return super.visitImport(imported);
279
+ let res = super.visitImport(imported);
280
+
281
+ restore();
282
+ return res;
202
283
  }
203
284
  }
204
285
 
205
286
  return CustomEvaluator;
206
287
  }
207
288
 
289
+ function patchNativeFS(fs, nativeGlob) {
290
+ let invalidations = [];
291
+ let readFileSync = nativeFS.readFileSync;
292
+ let statSync = nativeFS.statSync;
293
+
294
+ // $FlowFixMe
295
+ nativeFS.readFileSync = (filename, encoding) => {
296
+ return fs.readFileSync(filename, encoding);
297
+ };
298
+
299
+ // $FlowFixMe
300
+ nativeFS.statSync = p => {
301
+ try {
302
+ return fs.statSync(p);
303
+ } catch (err) {
304
+ // Track files that were checked but don't exist so that we watch for their creation.
305
+ if (!p.includes(`node_modules${path.sep}stylus`)) {
306
+ invalidations.push({filePath: p});
307
+ }
308
+ throw err;
309
+ }
310
+ };
311
+
312
+ // Patch the `glob` module as well so we use the Parcel FS and track invalidations.
313
+ let glob = nativeGlob.sync;
314
+ nativeGlob.sync = p => {
315
+ let res = globSync(p, fs);
316
+ if (!p.includes(`node_modules${path.sep}stylus`)) {
317
+ // Sometimes stylus passes file paths with no glob parts to the `glob` module.
318
+ // We want to avoid treating these as globs for performance.
319
+ if (isGlob(p)) {
320
+ invalidations.push({glob: p});
321
+ } else if (res.length === 0) {
322
+ invalidations.push({filePath: p});
323
+ }
324
+ }
325
+ return res;
326
+ };
327
+
328
+ return () => {
329
+ // $FlowFixMe
330
+ nativeFS.readFileSync = readFileSync;
331
+ // $FlowFixMe
332
+ nativeFS.statSync = statSync;
333
+ nativeGlob.sync = glob;
334
+ return invalidations;
335
+ };
336
+ }
337
+
208
338
  /**
209
339
  * Puts the content of all given node blocks into the first one, essentially merging them.
210
340
  */