@parcel/transformer-stylus 2.0.0-nightly.130 → 2.0.0-nightly.1303

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