@parcel/transformer-stylus 2.0.0-nightly.119 → 2.0.0-nightly.1190

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) === '.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,48 @@ 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
+ } else {
189
+ deps.set(importedPath, resolve(filepath, importedPath));
190
+ }
191
+ }
192
+
193
+ async function getDependencies(code, filepath, asset, resolve, options, parcelOptions, nativeGlob, seen = new Set(), includeImports = true) {
56
194
  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);
195
+ _nodes().default.filename = asset.filePath;
196
+ let parser = new (_parser().default)(code, options);
60
197
  let ast = parser.parse();
61
198
  let deps = new Map();
62
- new class extends DepsResolver {
199
+
200
+ if (includeImports && options.imports) {
201
+ for (let importedPath of options.imports) {
202
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
203
+ }
204
+ }
205
+
206
+ class ImportVisitor extends _depsResolver().default {
63
207
  visitImport(imported) {
64
208
  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
- }
209
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
75
210
  }
76
211
 
77
- }(ast, options).visit(ast); // Recursively process depdendencies, and return a map with all resolved paths.
212
+ }
213
+
214
+ new ImportVisitor(ast, options).visit(ast); // Recursively process depdendencies, and return a map with all resolved paths.
78
215
 
79
216
  let res = new Map();
80
217
  await Promise.all(Array.from(deps.entries()).map(async ([importedPath, resolved]) => {
@@ -86,7 +223,7 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
86
223
 
87
224
  let found;
88
225
 
89
- if (resolved) {
226
+ if (resolved && (!Array.isArray(resolved) || resolved.length > 0)) {
90
227
  found = Array.isArray(resolved) ? resolved : [resolved];
91
228
  res.set(importedPath, resolved);
92
229
  } else {
@@ -97,13 +234,20 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
97
234
 
98
235
  if (!/\.styl$/i.test(importedPath)) {
99
236
  importedPath += '.styl';
100
- }
237
+ } // Patch the native FS so we use Parcel's FS, and track files that are
238
+ // checked so we invalidate the cache when they are created.
239
+
101
240
 
102
- let paths = (options.paths || []).concat(_path.default.dirname(filepath || '.'));
103
- found = utils.find(importedPath, paths, filepath);
241
+ let restore = patchNativeFS(asset.fs, nativeGlob);
242
+ let paths = [...new Set((options.paths || []).concat(_path().default.dirname(filepath || '.')))];
243
+ found = _utils2().default.find(importedPath, paths, filepath);
104
244
 
105
245
  if (!found) {
106
- found = utils.lookupIndex(originalPath, paths, filepath);
246
+ found = _utils2().default.lookupIndex(originalPath, paths, filepath);
247
+ }
248
+
249
+ for (let invalidation of restore()) {
250
+ asset.invalidateOnFileCreate(invalidation);
107
251
  }
108
252
 
109
253
  if (!found) {
@@ -114,12 +258,10 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
114
258
 
115
259
  for (let resolved of found) {
116
260
  if (!seen.has(resolved)) {
117
- await asset.addIncludedFile({
118
- filePath: resolved
119
- });
261
+ await asset.invalidateOnFileChange(resolved);
120
262
  let code = await asset.fs.readFile(resolved, 'utf8');
121
263
 
122
- for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, seen)) {
264
+ for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, nativeGlob, seen, false)) {
123
265
  res.set(path, resolvedPath);
124
266
  }
125
267
  }
@@ -128,13 +270,12 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
128
270
  return res;
129
271
  }
130
272
 
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
273
+ async function createEvaluator(code, asset, resolve, options, parcelOptions, nativeGlob) {
274
+ 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
275
  // require resolution algorithm. It also adds all dependencies to the parcel asset
135
276
  // tree so the file watcher works correctly, etc.
136
277
 
137
- return class extends Evaluator {
278
+ class CustomEvaluator extends _evaluator().default {
138
279
  visitImport(imported) {
139
280
  let node = this.visit(imported.path).first;
140
281
  let path = node.string;
@@ -152,16 +293,86 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
152
293
  // replace it with a separate import node for each file
153
294
  return mergeBlocks(resolved.map(resolvedPath => {
154
295
  node.string = resolvedPath;
155
- return super.visitImport(imported.clone());
296
+ let restore = patchNativeFS(asset.fs, nativeGlob);
297
+ let res = super.visitImport(imported.clone());
298
+ restore();
299
+ return res;
156
300
  }));
157
301
  }
158
302
  }
159
- } // Done. Let stylus do its thing.
303
+ } // Patch the native FS so stylus uses Parcel's FS to read the file.
304
+
305
+
306
+ let restore = patchNativeFS(asset.fs, nativeGlob); // Done. Let stylus do its thing.
307
+
308
+ let res = super.visitImport(imported);
309
+ restore();
310
+ return res;
311
+ }
312
+
313
+ }
314
+
315
+ return CustomEvaluator;
316
+ }
317
+
318
+ function patchNativeFS(fs, nativeGlob) {
319
+ let invalidations = [];
320
+
321
+ let readFileSync = _fs().default.readFileSync;
322
+
323
+ let statSync = _fs().default.statSync; // $FlowFixMe
324
+
325
+
326
+ _fs().default.readFileSync = (filename, encoding) => {
327
+ return fs.readFileSync(filename, encoding);
328
+ }; // $FlowFixMe
329
+
330
+
331
+ _fs().default.statSync = p => {
332
+ try {
333
+ return fs.statSync(p);
334
+ } catch (err) {
335
+ // Track files that were checked but don't exist so that we watch for their creation.
336
+ if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
337
+ invalidations.push({
338
+ filePath: p
339
+ });
340
+ }
341
+
342
+ throw err;
343
+ }
344
+ }; // Patch the `glob` module as well so we use the Parcel FS and track invalidations.
345
+
346
+
347
+ let glob = nativeGlob.sync;
160
348
 
349
+ nativeGlob.sync = p => {
350
+ let res = (0, _utils().globSync)(p, fs);
161
351
 
162
- return super.visitImport(imported);
352
+ if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
353
+ // Sometimes stylus passes file paths with no glob parts to the `glob` module.
354
+ // We want to avoid treating these as globs for performance.
355
+ if ((0, _utils().isGlob)(p)) {
356
+ invalidations.push({
357
+ glob: p
358
+ });
359
+ } else if (res.length === 0) {
360
+ invalidations.push({
361
+ filePath: p
362
+ });
363
+ }
163
364
  }
164
365
 
366
+ return res;
367
+ };
368
+
369
+ return () => {
370
+ // $FlowFixMe
371
+ _fs().default.readFileSync = readFileSync; // $FlowFixMe
372
+
373
+ _fs().default.statSync = statSync;
374
+ nativeGlob.sync = glob;
375
+ return invalidations;
165
376
  };
166
377
  }
167
378
  /**
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "@parcel/transformer-stylus",
3
- "version": "2.0.0-nightly.119+706a7e64",
3
+ "version": "2.0.0-nightly.1190+c4a898c0f",
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.1188+c4a898c0f"
17
21
  },
18
22
  "dependencies": {
19
- "@parcel/plugin": "2.0.0-nightly.119+706a7e64",
20
- "@parcel/utils": "2.0.0-nightly.119+706a7e64"
21
- },
22
- "devDependencies": {
23
- "stylus": "^0.54.5"
23
+ "@parcel/plugin": "2.0.0-nightly.1190+c4a898c0f",
24
+ "@parcel/utils": "2.0.0-nightly.1190+c4a898c0f",
25
+ "stylus": "^0.55.0"
24
26
  },
25
- "gitHead": "706a7e647f90c65724f6b3560376c9ffab80eb5e"
27
+ "gitHead": "c4a898c0fd9f001875fe23157e230c24778aefe8"
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) === '.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,37 @@ 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
+ ),
106
+ ),
107
+ ),
108
+ );
109
+ } else {
110
+ deps.set(importedPath, resolve(filepath, importedPath));
111
+ }
112
+ }
40
113
 
41
114
  async function getDependencies(
42
115
  code,
@@ -45,14 +118,11 @@ async function getDependencies(
45
118
  resolve,
46
119
  options,
47
120
  parcelOptions,
121
+ nativeGlob,
48
122
  seen = new Set(),
123
+ includeImports = true,
49
124
  ) {
50
125
  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
126
 
57
127
  nodes.filename = asset.filePath;
58
128
 
@@ -60,35 +130,16 @@ async function getDependencies(
60
130
  let ast = parser.parse();
61
131
  let deps = new Map();
62
132
 
133
+ if (includeImports && options.imports) {
134
+ for (let importedPath of options.imports) {
135
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
136
+ }
137
+ }
138
+
63
139
  class ImportVisitor extends DepsResolver {
64
140
  visitImport(imported) {
65
141
  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
- }
142
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
92
143
  }
93
144
  }
94
145
 
@@ -105,7 +156,7 @@ async function getDependencies(
105
156
  }
106
157
 
107
158
  let found;
108
- if (resolved) {
159
+ if (resolved && (!Array.isArray(resolved) || resolved.length > 0)) {
109
160
  found = Array.isArray(resolved) ? resolved : [resolved];
110
161
  res.set(importedPath, resolved);
111
162
  } else {
@@ -118,12 +169,24 @@ async function getDependencies(
118
169
  importedPath += '.styl';
119
170
  }
120
171
 
121
- let paths = (options.paths || []).concat(path.dirname(filepath || '.'));
172
+ // Patch the native FS so we use Parcel's FS, and track files that are
173
+ // checked so we invalidate the cache when they are created.
174
+ let restore = patchNativeFS(asset.fs, nativeGlob);
175
+
176
+ let paths = [
177
+ ...new Set(
178
+ (options.paths || []).concat(path.dirname(filepath || '.')),
179
+ ),
180
+ ];
122
181
  found = utils.find(importedPath, paths, filepath);
123
182
  if (!found) {
124
183
  found = utils.lookupIndex(originalPath, paths, filepath);
125
184
  }
126
185
 
186
+ for (let invalidation of restore()) {
187
+ asset.invalidateOnFileCreate(invalidation);
188
+ }
189
+
127
190
  if (!found) {
128
191
  throw new Error('failed to locate file ' + originalPath);
129
192
  }
@@ -132,7 +195,7 @@ async function getDependencies(
132
195
  // Recursively process resolved files as well to get nested deps
133
196
  for (let resolved of found) {
134
197
  if (!seen.has(resolved)) {
135
- await asset.addIncludedFile({filePath: resolved});
198
+ await asset.invalidateOnFileChange(resolved);
136
199
 
137
200
  let code = await asset.fs.readFile(resolved, 'utf8');
138
201
  for (let [path, resolvedPath] of await getDependencies(
@@ -142,7 +205,9 @@ async function getDependencies(
142
205
  resolve,
143
206
  options,
144
207
  parcelOptions,
208
+ nativeGlob,
145
209
  seen,
210
+ false,
146
211
  )) {
147
212
  res.set(path, resolvedPath);
148
213
  }
@@ -154,7 +219,14 @@ async function getDependencies(
154
219
  return res;
155
220
  }
156
221
 
157
- async function createEvaluator(code, asset, resolve, options, parcelOptions) {
222
+ async function createEvaluator(
223
+ code,
224
+ asset,
225
+ resolve,
226
+ options,
227
+ parcelOptions,
228
+ nativeGlob,
229
+ ) {
158
230
  const deps = await getDependencies(
159
231
  code,
160
232
  asset.filePath,
@@ -162,10 +234,7 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
162
234
  resolve,
163
235
  options,
164
236
  parcelOptions,
165
- );
166
- const Evaluator = await parcelOptions.packageManager.require(
167
- 'stylus/lib/visitor/evaluator',
168
- asset.filePath,
237
+ nativeGlob,
169
238
  );
170
239
 
171
240
  // This is a custom stylus evaluator that extends stylus with support for the node
@@ -190,21 +259,79 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
190
259
  return mergeBlocks(
191
260
  resolved.map(resolvedPath => {
192
261
  node.string = resolvedPath;
193
- return super.visitImport(imported.clone());
262
+ let restore = patchNativeFS(asset.fs, nativeGlob);
263
+ let res = super.visitImport(imported.clone());
264
+ restore();
265
+ return res;
194
266
  }),
195
267
  );
196
268
  }
197
269
  }
198
270
  }
199
271
 
272
+ // Patch the native FS so stylus uses Parcel's FS to read the file.
273
+ let restore = patchNativeFS(asset.fs, nativeGlob);
274
+
200
275
  // Done. Let stylus do its thing.
201
- return super.visitImport(imported);
276
+ let res = super.visitImport(imported);
277
+
278
+ restore();
279
+ return res;
202
280
  }
203
281
  }
204
282
 
205
283
  return CustomEvaluator;
206
284
  }
207
285
 
286
+ function patchNativeFS(fs, nativeGlob) {
287
+ let invalidations = [];
288
+ let readFileSync = nativeFS.readFileSync;
289
+ let statSync = nativeFS.statSync;
290
+
291
+ // $FlowFixMe
292
+ nativeFS.readFileSync = (filename, encoding) => {
293
+ return fs.readFileSync(filename, encoding);
294
+ };
295
+
296
+ // $FlowFixMe
297
+ nativeFS.statSync = p => {
298
+ try {
299
+ return fs.statSync(p);
300
+ } catch (err) {
301
+ // Track files that were checked but don't exist so that we watch for their creation.
302
+ if (!p.includes(`node_modules${path.sep}stylus`)) {
303
+ invalidations.push({filePath: p});
304
+ }
305
+ throw err;
306
+ }
307
+ };
308
+
309
+ // Patch the `glob` module as well so we use the Parcel FS and track invalidations.
310
+ let glob = nativeGlob.sync;
311
+ nativeGlob.sync = p => {
312
+ let res = globSync(p, fs);
313
+ if (!p.includes(`node_modules${path.sep}stylus`)) {
314
+ // Sometimes stylus passes file paths with no glob parts to the `glob` module.
315
+ // We want to avoid treating these as globs for performance.
316
+ if (isGlob(p)) {
317
+ invalidations.push({glob: p});
318
+ } else if (res.length === 0) {
319
+ invalidations.push({filePath: p});
320
+ }
321
+ }
322
+ return res;
323
+ };
324
+
325
+ return () => {
326
+ // $FlowFixMe
327
+ nativeFS.readFileSync = readFileSync;
328
+ // $FlowFixMe
329
+ nativeFS.statSync = statSync;
330
+ nativeGlob.sync = glob;
331
+ return invalidations;
332
+ };
333
+ }
334
+
208
335
  /**
209
336
  * Puts the content of all given node blocks into the first one, essentially merging them.
210
337
  */