-
Notifications
You must be signed in to change notification settings - Fork 50
Add support for Sass includePaths option
#55
Changes from all commits
89f376b
0af1687
6bc4dbe
ee81783
2e29769
8902b1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import path from 'path'; | ||
| import fs from 'fs'; | ||
| import toutSuite from 'toutsuite'; | ||
|
|
||
| import {CompilerBase} from '../compiler-base'; | ||
|
|
@@ -48,15 +49,21 @@ export default class SassCompiler extends CompilerBase { | |
|
|
||
| paths.unshift('.'); | ||
|
|
||
| const { includePaths } = this.compilerOptions; | ||
| if (includePaths) { | ||
| sass.importer(this.buildImporterCallback(includePaths)); | ||
| delete this.compilerOptions.includePaths; | ||
| } | ||
|
|
||
| let opts = Object.assign({}, this.compilerOptions, { | ||
| indentedSyntax: filePath.match(/\.sass$/i), | ||
| sourceMapRoot: filePath, | ||
| sourceMapRoot: filePath, | ||
| }); | ||
|
|
||
| let result = await new Promise((res,rej) => { | ||
| sass.compile(sourceCode, opts, (r) => { | ||
| if (r.status !== 0) { | ||
| rej(new Error(r.formatted)); | ||
| rej(new Error(r.formatted || r.message)); | ||
| return; | ||
| } | ||
|
|
||
|
|
@@ -93,9 +100,15 @@ export default class SassCompiler extends CompilerBase { | |
|
|
||
| paths.unshift('.'); | ||
|
|
||
| const { includePaths } = this.compilerOptions; | ||
| if (includePaths) { | ||
| sass.importer(this.buildImporterCallback(includePaths)); | ||
| delete this.compilerOptions.includePaths; | ||
| } | ||
|
|
||
| let opts = Object.assign({}, this.compilerOptions, { | ||
| indentedSyntax: filePath.match(/\.sass$/i), | ||
| sourceMapRoot: filePath, | ||
| sourceMapRoot: filePath, | ||
| }); | ||
|
|
||
| let result; | ||
|
|
@@ -114,8 +127,75 @@ export default class SassCompiler extends CompilerBase { | |
| }; | ||
| } | ||
|
|
||
| buildImporterCallback (includePaths) { | ||
| const self = this; | ||
| return (function (request, done) { | ||
| let file; | ||
| if (request.file) { | ||
| done(); | ||
| return; | ||
| } else { | ||
| // sass.js works in the '/sass/' directory | ||
| const cleanedRequestPath = request.resolved.replace(/^\/sass\//, ''); | ||
| for (let includePath of includePaths) { | ||
| const filePath = path.resolve(includePath, cleanedRequestPath); | ||
| let variations = sass.getPathVariations(filePath); | ||
|
|
||
| file = variations | ||
| .map(self.fixWindowsPath.bind(self)) | ||
| .reduce(self.importedFileReducer.bind(self), null); | ||
|
|
||
| if (file) { | ||
| const content = fs.readFileSync(file, { encoding: 'utf8' }); | ||
| return sass.writeFile(file, content, () => { | ||
| done({ path: file }); | ||
| return; | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| if (!file) { | ||
| done(); | ||
| return; | ||
| } | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| importedFileReducer(found, path) { | ||
| // Find the first variation that actually exists | ||
| if (found) return found; | ||
|
|
||
| try { | ||
| const stat = fs.statSync(path); | ||
| if (!stat.isFile()) return null; | ||
| return path; | ||
| } catch(e) { | ||
| return null; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably want to debug log this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about this - sass.js returns ~25 variations, each invalid one will fail here and trigger a debug log. In medium-sized projects with multiple sass files, this will generate a whole lot of unnecessary output. Correct me if I'm wrong :)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @saschagehlich Use the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know about the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, in that case we'll just hope that Sass provides enough debugging
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If sass.js doesn't find an imported file, it reports an error anyway, so I guess that's fine |
||
| } | ||
| } | ||
|
|
||
| fixWindowsPath(file) { | ||
| // Unfortunately, there's a bug in sass.js that seems to ignore the different | ||
| // path separators across platforms | ||
|
|
||
| // For some reason, some files have a leading slash that we need to get rid of | ||
| if (process.platform === 'win32' && file[0] === '/') { | ||
| file = file.slice(1); | ||
| } | ||
|
|
||
| // Sass.js generates paths such as `_C:\myPath\file.sass` instead of `C:\myPath\_file.sass` | ||
| if (file[0] === '_') { | ||
| const parts = file.slice(1).split(path.sep); | ||
| const dir = parts.slice(0, -1).join(path.sep); | ||
| const fileName = parts.reverse()[0]; | ||
| file = path.resolve(dir, '_' + fileName); | ||
| } | ||
| return file; | ||
| } | ||
|
|
||
| getCompilerVersion() { | ||
| // NB: There is a bizarre bug in the node module system where this doesn't | ||
| // NB: There is a bizarre bug in the node module system where this doesn't | ||
| // work but only in saveConfiguration tests | ||
| //return require('@paulcbetts/node-sass/package.json').version; | ||
| return "4.1.1"; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing return statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅