@parcel/transformer-stylus 2.0.0-nightly.149 → 2.0.0-nightly.1491

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,168 @@ 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 = exports.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
- exports.default = _default;
54
-
55
- async function getDependencies(code, filepath, asset, resolve, options, parcelOptions, seen = new Set()) {
128
+ function attemptResolve(importedPath, filepath, asset, resolve, deps) {
129
+ if (deps.has(importedPath)) {
130
+ return;
131
+ }
132
+ if ((0, _utils().isGlob)(importedPath)) {
133
+ // Invalidate when new files are created that match the glob pattern.
134
+ let absoluteGlob = _path().default.resolve(_path().default.dirname(filepath), importedPath);
135
+ asset.invalidateOnFileCreate({
136
+ glob: absoluteGlob
137
+ });
138
+ deps.set(importedPath, (0, _utils().glob)(absoluteGlob, asset.fs, {
139
+ onlyFiles: true
140
+ }).then(entries => Promise.all(entries.map(entry => resolve(filepath, './' + _path().default.relative(_path().default.dirname(filepath), entry), {
141
+ packageConditions: ['stylus', 'style']
142
+ })))));
143
+ } else {
144
+ deps.set(importedPath, resolve(filepath, importedPath, {
145
+ packageConditions: ['stylus', 'style']
146
+ }));
147
+ }
148
+ }
149
+ async function getDependencies(code, filepath, asset, resolve, options, parcelOptions, nativeGlob, seen = new Set(), includeImports = true) {
56
150
  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);
151
+ _nodes().default.filename = asset.filePath;
152
+ let parser = new (_parser().default)(code, options);
60
153
  let ast = parser.parse();
61
154
  let deps = new Map();
62
- new class extends DepsResolver {
155
+ if (includeImports && options.imports) {
156
+ for (let importedPath of options.imports) {
157
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
158
+ }
159
+ }
160
+ class ImportVisitor extends _depsResolver().default {
63
161
  visitImport(imported) {
64
162
  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
- }
163
+ attemptResolve(importedPath, filepath, asset, resolve, deps);
75
164
  }
165
+ }
166
+ new ImportVisitor(ast, options).visit(ast);
76
167
 
77
- }(ast, options).visit(ast); // Recursively process depdendencies, and return a map with all resolved paths.
78
-
168
+ // Recursively process depdendencies, and return a map with all resolved paths.
79
169
  let res = new Map();
80
170
  await Promise.all(Array.from(deps.entries()).map(async ([importedPath, resolved]) => {
81
171
  try {
@@ -83,43 +173,42 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
83
173
  } catch (err) {
84
174
  resolved = null;
85
175
  }
86
-
87
176
  let found;
88
-
89
- if (resolved) {
177
+ if (resolved && (!Array.isArray(resolved) || resolved.length > 0)) {
90
178
  found = Array.isArray(resolved) ? resolved : [resolved];
91
179
  res.set(importedPath, resolved);
92
180
  } else {
93
181
  // If we couldn't resolve, try the normal stylus resolver.
94
182
  // We just need to do this to keep track of the dependencies - stylus does the real work.
183
+
95
184
  // support optional .styl
96
185
  let originalPath = importedPath;
97
-
98
186
  if (!/\.styl$/i.test(importedPath)) {
99
187
  importedPath += '.styl';
100
188
  }
101
189
 
102
- let paths = (options.paths || []).concat(_path.default.dirname(filepath || '.'));
103
- found = utils.find(importedPath, paths, filepath);
104
-
190
+ // Patch the native FS so we use Parcel's FS, and track files that are
191
+ // checked so we invalidate the cache when they are created.
192
+ let restore = patchNativeFS(asset.fs, nativeGlob);
193
+ let paths = [...new Set((options.paths || []).concat(_path().default.dirname(filepath || '.')))];
194
+ found = _utils2().default.find(importedPath, paths, filepath);
105
195
  if (!found) {
106
- found = utils.lookupIndex(originalPath, paths, filepath);
196
+ found = _utils2().default.lookupIndex(originalPath, paths, filepath);
197
+ }
198
+ for (let invalidation of restore()) {
199
+ asset.invalidateOnFileCreate(invalidation);
107
200
  }
108
-
109
201
  if (!found) {
110
202
  throw new Error('failed to locate file ' + originalPath);
111
203
  }
112
- } // Recursively process resolved files as well to get nested deps
113
-
204
+ }
114
205
 
206
+ // Recursively process resolved files as well to get nested deps
115
207
  for (let resolved of found) {
116
208
  if (!seen.has(resolved)) {
117
- await asset.addIncludedFile({
118
- filePath: resolved
119
- });
209
+ asset.invalidateOnFileChange(resolved);
120
210
  let code = await asset.fs.readFile(resolved, 'utf8');
121
-
122
- for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, seen)) {
211
+ for (let [path, resolvedPath] of await getDependencies(code, resolved, asset, resolve, options, parcelOptions, nativeGlob, seen, false)) {
123
212
  res.set(path, resolvedPath);
124
213
  }
125
214
  }
@@ -127,23 +216,22 @@ async function getDependencies(code, filepath, asset, resolve, options, parcelOp
127
216
  }));
128
217
  return res;
129
218
  }
219
+ async function createEvaluator(code, asset, resolve, options, parcelOptions, nativeGlob) {
220
+ const deps = await getDependencies(code, asset.filePath, asset, resolve, options, parcelOptions, nativeGlob);
130
221
 
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
222
+ // This is a custom stylus evaluator that extends stylus with support for the node
134
223
  // require resolution algorithm. It also adds all dependencies to the parcel asset
135
224
  // tree so the file watcher works correctly, etc.
136
-
137
- return class extends Evaluator {
225
+ class CustomEvaluator extends _evaluator().default {
138
226
  visitImport(imported) {
139
227
  let node = this.visit(imported.path).first;
140
228
  let path = node.string;
141
-
142
229
  if (node.name !== 'url' && path && !URL_RE.test(path)) {
143
- let resolved = deps.get(path); // First try resolving using the node require resolution algorithm.
230
+ let resolved = deps.get(path);
231
+
232
+ // First try resolving using the node require resolution algorithm.
144
233
  // This allows stylus files in node_modules to be resolved properly.
145
234
  // If we find something, update the AST so stylus gets the absolute path to load later.
146
-
147
235
  if (resolved) {
148
236
  if (!Array.isArray(resolved)) {
149
237
  node.string = resolved;
@@ -152,26 +240,85 @@ async function createEvaluator(code, asset, resolve, options, parcelOptions) {
152
240
  // replace it with a separate import node for each file
153
241
  return mergeBlocks(resolved.map(resolvedPath => {
154
242
  node.string = resolvedPath;
155
- return super.visitImport(imported.clone());
243
+ let restore = patchNativeFS(asset.fs, nativeGlob);
244
+ let res = super.visitImport(imported.clone());
245
+ restore();
246
+ return res;
156
247
  }));
157
248
  }
158
249
  }
159
- } // Done. Let stylus do its thing.
250
+ }
160
251
 
252
+ // Patch the native FS so stylus uses Parcel's FS to read the file.
253
+ let restore = patchNativeFS(asset.fs, nativeGlob);
161
254
 
162
- return super.visitImport(imported);
255
+ // Done. Let stylus do its thing.
256
+ let res = super.visitImport(imported);
257
+ restore();
258
+ return res;
163
259
  }
260
+ }
261
+ return CustomEvaluator;
262
+ }
263
+ function patchNativeFS(fs, nativeGlob) {
264
+ let invalidations = [];
265
+ let readFileSync = _fs().default.readFileSync;
266
+ let statSync = _fs().default.statSync;
267
+
268
+ // $FlowFixMe
269
+ _fs().default.readFileSync = (filename, encoding) => {
270
+ return fs.readFileSync(filename, encoding);
271
+ };
272
+
273
+ // $FlowFixMe
274
+ _fs().default.statSync = p => {
275
+ try {
276
+ return fs.statSync(p);
277
+ } catch (err) {
278
+ // Track files that were checked but don't exist so that we watch for their creation.
279
+ if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
280
+ invalidations.push({
281
+ filePath: p
282
+ });
283
+ }
284
+ throw err;
285
+ }
286
+ };
164
287
 
288
+ // Patch the `glob` module as well so we use the Parcel FS and track invalidations.
289
+ let glob = nativeGlob.sync;
290
+ nativeGlob.sync = p => {
291
+ let res = (0, _utils().globSync)(p, fs);
292
+ if (!p.includes(`node_modules${_path().default.sep}stylus`)) {
293
+ // Sometimes stylus passes file paths with no glob parts to the `glob` module.
294
+ // We want to avoid treating these as globs for performance.
295
+ if ((0, _utils().isGlob)(p)) {
296
+ invalidations.push({
297
+ glob: p
298
+ });
299
+ } else if (res.length === 0) {
300
+ invalidations.push({
301
+ filePath: p
302
+ });
303
+ }
304
+ }
305
+ return res;
306
+ };
307
+ return () => {
308
+ // $FlowFixMe
309
+ _fs().default.readFileSync = readFileSync;
310
+ // $FlowFixMe
311
+ _fs().default.statSync = statSync;
312
+ nativeGlob.sync = glob;
313
+ return invalidations;
165
314
  };
166
315
  }
316
+
167
317
  /**
168
318
  * Puts the content of all given node blocks into the first one, essentially merging them.
169
319
  */
170
-
171
-
172
320
  function mergeBlocks(blocks) {
173
321
  let finalBlock;
174
-
175
322
  for (const block of blocks) {
176
323
  if (finalBlock) {
177
324
  // $FlowFixMe - finalBlock is definitely defined
@@ -180,6 +327,5 @@ function mergeBlocks(blocks) {
180
327
  finalBlock = block;
181
328
  }
182
329
  }
183
-
184
330
  return finalBlock;
185
331
  }
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "@parcel/transformer-stylus",
3
- "version": "2.0.0-nightly.149+453f7b0b",
3
+ "version": "2.0.0-nightly.1491+fdf495ba3",
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.1489+fdf495ba3"
17
21
  },
18
22
  "dependencies": {
19
- "@parcel/plugin": "2.0.0-nightly.149+453f7b0b",
20
- "@parcel/utils": "2.0.0-nightly.149+453f7b0b"
21
- },
22
- "devDependencies": {
23
- "stylus": "^0.54.5"
23
+ "@parcel/plugin": "2.0.0-nightly.1491+fdf495ba3",
24
+ "@parcel/utils": "2.0.0-nightly.1491+fdf495ba3",
25
+ "stylus": "^0.55.0"
24
26
  },
25
- "gitHead": "453f7b0bf295e6a7cbec5d24fab4c48e21e6168f"
27
+ "gitHead": "fdf495ba3c8ed727d10e87cc9697bc9ef5ec997a"
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
+ 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
  */