@parcel/transformer-stylus 2.0.0-nightly.127 → 2.0.0-nightly.1273

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