Skip to content

Commit 510c1c8

Browse files
wkillerudxzyfer
andauthored
Migrate to use the new Sass JS API by default (#846)
* Migrate to use the new Sass JS API by default Keep the legacy API around, since its removal is still probably a while from now. Fixes #837 * Update README for the next major version Add a migration section, link to relevant Sass documentation, and add a section about still using the legacy API. * Update tests to support the new API, sass-embedded * Prepare changelog entry for the next major version * Update CHANGELOG.md --------- Co-authored-by: Michael Mifsud <[email protected]>
1 parent c04bb67 commit 510c1c8

File tree

7 files changed

+829
-75
lines changed

7 files changed

+829
-75
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# gulp-sass Changelog
22

3+
## v6.0.0
4+
5+
**November 27, 2024**
6+
7+
<https://github.com/dlmanning/gulp-sass/releases/tag/v6.0.0>
8+
39
## v5.0.0
410

511
**June 25, 2021**

README.md

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ Sass plugin for [Gulp](https://github.com/gulpjs/gulp).
44

55
**_Before filing an issue, please make sure you have [updated to the latest version of `gulp-sass`](https://github.com/dlmanning/gulp-sass/wiki/Update-to-the-latest-Gulp-Sass) and have gone through our [Common Issues and Their Fixes](https://github.com/dlmanning/gulp-sass/wiki/Common-Issues-and-Their-Fixes) section._**
66

7-
**Migrating your existing project to version 5? Please read our (short!) [migration guide](#migrating-to-version-5).**
7+
**Migrating your existing project to version 5 or 6? Please read our (short!) [migration guides](#migrating-to-version-6).**
88

99
## Support
1010

1111
Only [Active LTS and Current releases](https://github.com/nodejs/Release#release-schedule) are supported.
1212

1313
## Installation
1414

15-
To use `gulp-sass`, you must install both `gulp-sass` itself *and* a Sass compiler. `gulp-sass` supports both [Dart Sass][] and [Node Sass][], although Node Sass is [deprecated](https://sass-lang.com/blog/libsass-is-deprecated). We recommend that you use Dart Sass for new projects, and migrate Node Sass projects to Dart Sass when possible.
15+
To use `gulp-sass`, you must install both `gulp-sass` itself *and* a Sass compiler. `gulp-sass` supports both [Embedded Sass][], [Dart Sass][] and [Node Sass][], although Node Sass is [deprecated](https://sass-lang.com/blog/libsass-is-deprecated). We recommend that you use Dart Sass for new projects, and migrate Node Sass projects to Dart Sass or Embedded Sass when possible.
1616

1717
Whichever compiler you choose, it's best to install these as dev dependencies:
1818

@@ -42,7 +42,7 @@ const sass = gulpSass(dartSass);
4242

4343
`gulp-sass` must be used in a Gulp task. Your task can call `sass()` (to asynchronously render your CSS), or `sass.sync()` (to synchronously render your CSS). Then, export your task with the `export` keyword. We'll show some examples of how to do that.
4444

45-
**⚠️ Note:** When using Dart Sass, **synchronous rendering is twice as fast as asynchronous rendering**. The Sass team is exploring ways to improve asynchronous rendering with Dart Sass, but for now, you will get the best performance from `sass.sync()`. If performance is critical, you can use `node-sass` instead, but bear in mind that `node-sass` may not support modern Sass features you rely on.
45+
**⚠️ Note:** When using Dart Sass, **synchronous rendering is twice as fast as asynchronous rendering**. The Sass team is exploring ways to improve asynchronous rendering with Dart Sass, but for now, you will get the best performance from `sass.sync()`. If performance is critical, you can use `sass-embedded` instead.
4646

4747
### Render your CSS
4848

@@ -78,17 +78,17 @@ function buildStyles() {
7878

7979
### Render with options
8080

81-
To change the final output of your CSS, you can pass an options object to your renderer. `gulp-sass` supports [Node Sass's render options](https://github.com/sass/node-sass#options), with two unsupported exceptions:
81+
To change the final output of your CSS, you can pass an options object to your renderer. `gulp-sass` supports [Sass's JS API compile options](https://sass-lang.com/documentation/js-api/modules#compileString), with a few usage notes:
8282

83-
- The `data` option, which is used by `gulp-sass` internally.
84-
- The `file` option, which has undefined behavior that may change without notice.
83+
- The `syntax` option is set to `indented` automatically for files with the `.sass` extension
84+
- The `sourceMap` and `sourceMapIncludeSources` options are set for you when using `gulp-sourcemaps`
8585

86-
For example, to compress your CSS, you can call `sass({outputStyle: 'compressed'}`. In the context of a Gulp task, that looks like this:
86+
For example, to compress your CSS, you can call `sass({style: 'compressed'}`. In the context of a Gulp task, that looks like this:
8787

8888
```js
8989
function buildStyles() {
9090
return gulp.src('./sass/**/*.scss')
91-
.pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
91+
.pipe(sass({style: 'compressed'}).on('error', sass.logError))
9292
.pipe(gulp.dest('./css'));
9393
};
9494

@@ -100,7 +100,7 @@ Or this for synchronous rendering:
100100
```js
101101
function buildStyles() {
102102
return gulp.src('./sass/**/*.scss')
103-
.pipe(sass.sync({outputStyle: 'compressed'}).on('error', sass.logError))
103+
.pipe(sass.sync({style: 'compressed'}).on('error', sass.logError))
104104
.pipe(gulp.dest('./css'));
105105
};
106106

@@ -141,13 +141,34 @@ function buildStyles() {
141141
exports.buildStyles = buildStyles;
142142
```
143143

144+
<h2 id="migrating-to-version-6">Migrating to version 6</h2>
145+
146+
`gulp-sass` version 6 uses the new [compile](https://sass-lang.com/documentation/js-api/modules#compileString) function internally by default. If you use any options, for instance custom importers, please compare the [new options](https://sass-lang.com/documentation/js-api/modules#compileString) with the [legacy options](https://sass-lang.com/documentation/js-api/modules#render) in order to migrate. For instance, the `outputStyle` option is now called `style`.
147+
148+
```diff
149+
function buildStyles() {
150+
return gulp.src('./sass/**/*.scss')
151+
- .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
152+
+ .pipe(sass({style: 'compressed'}).on('error', sass.logError))
153+
.pipe(gulp.dest('./css'));
154+
};
155+
```
156+
157+
If you want to keep using the legacy API while it's available, you can.
158+
159+
```js
160+
const sass = require('gulp-sass/legacy')(require('sass'));
161+
```
162+
163+
If you use source maps, you may see the result change somewhat. The result will typically be absolute `file:` URLs, rather than relative ones. The result may also be the source itself, URL encoded. You can [optionally add custom importers](https://sass-lang.com/documentation/js-api/interfaces/CompileResult#sourceMap) to adjust the source maps according to your own needs.
164+
144165
<h2 id="migrating-to-version-5">Migrating to version 5</h2>
145166

146167
`gulp-sass` version 5 requires Node.js 12 or later, and introduces some breaking changes. Additionally, changes in Node.js itself mean that Node fibers can no longer be used to speed up Dart Sass in Node.js 16.
147168

148169
### Setting a Sass compiler
149170

150-
As of version 5, `gulp-sass` _does not include a default Sass compiler_, so you must install one (either `node-sass` or `sass`) along with `gulp-sass`.
171+
As of version 5, `gulp-sass` _does not include a default Sass compiler_, so you must install one (either `sass`, `sass-embedded`, or `node-sass`) along with `gulp-sass`.
151172

152173
```sh
153174
npm install sass gulp-sass --save-dev
@@ -176,6 +197,28 @@ import dartSass from 'sass';
176197
+ const sass = gulpSass(dartSass);
177198
```
178199

200+
### Using the legacy Sass API
201+
202+
If you need to use the deprecated `render` Sass API, `gulp-sass` still includes legacy support.
203+
204+
```js
205+
'use strict';
206+
207+
const gulp = require('gulp');
208+
const sass = require('gulp-sass/legacy')(require('sass'));
209+
210+
function buildStyles() {
211+
return gulp.src('./sass/**/*.scss')
212+
.pipe(sass().on('error', sass.logError))
213+
.pipe(gulp.dest('./css'));
214+
};
215+
216+
exports.buildStyles = buildStyles;
217+
exports.watch = function () {
218+
gulp.watch('./sass/**/*.scss', ['sass']);
219+
};
220+
````
221+
179222
### What about fibers?
180223

181224
We used to recommend Node fibers as a way to speed up asynchronous rendering with Dart Sass. Unfortunately, [Node fibers are discontinued](https://sass-lang.com/blog/node-fibers-discontinued) and will not work in Node.js 16. The Sass team is exploring its options for future performance improvements, but for now, you will get the best performance from `sass.sync()`.
@@ -190,6 +233,7 @@ If you're having problems with the options you're passing in, it's likely a Dart
190233

191234
We may, in the course of resolving issues, direct you to one of these other projects. If we do so, please follow up by searching that project's issue queue (both open and closed) for your problem and, if it doesn't exist, filing an issue with them.
192235

236+
[Embedded Sass]: https://github.com/sass/embedded-host-node
193237
[Dart Sass]: https://sass-lang.com/dart-sass
194238
[LibSass]: https://sass-lang.com/libsass
195239
[Node Sass]: https://github.com/sass/node-sass

index.js

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@ const transfob = (transform) => new Transform({ transform, objectMode: true });
2424
/**
2525
* Handles returning the file to the stream
2626
*/
27-
const filePush = (file, sassObject, callback) => {
27+
const filePush = (file, compileResult, callback) => {
28+
file.contents = Buffer.from(compileResult.css);
29+
file.path = replaceExtension(file.path, '.css');
30+
2831
// Build Source Maps!
29-
if (sassObject.map) {
30-
// Transform map into JSON
31-
const sassMap = JSON.parse(sassObject.map.toString());
32+
if (compileResult.sourceMap) {
33+
const sassMap = compileResult.sourceMap;
34+
if (!sassMap.file) {
35+
sassMap.file = file.path;
36+
}
37+
3238
// Grab the stdout and transform it into stdin
3339
const sassMapFile = sassMap.file.replace(/^stdout$/, 'stdin');
3440
// Grab the base filename that's being worked on
@@ -55,9 +61,6 @@ const filePush = (file, sassObject, callback) => {
5561
applySourceMap(file, sassMap);
5662
}
5763

58-
file.contents = sassObject.css;
59-
file.path = replaceExtension(file.path, '.css');
60-
6164
if (file.stat) {
6265
file.stat.atime = file.stat.mtime = file.stat.ctime = new Date();
6366
}
@@ -71,7 +74,7 @@ const filePush = (file, sassObject, callback) => {
7174
const handleError = (error, file, callback) => {
7275
const filePath = (error.file === 'stdin' ? file.path : error.file) || file.path;
7376
const relativePath = path.relative(process.cwd(), filePath);
74-
const message = `${picocolors.underline(relativePath)}\n${error.formatted}`;
77+
const message = `${picocolors.underline(relativePath)}\n${error.message}`;
7578

7679
error.messageFormatted = message;
7780
error.messageOriginal = error.message;
@@ -110,52 +113,48 @@ const gulpSass = (options, sync) => {
110113
}
111114

112115
const opts = clonedeep(options || {});
113-
opts.data = file.contents.toString();
114116

115-
// We set the file path here so that libsass can correctly resolve import paths
116-
opts.file = file.path;
117-
118-
// Ensure `indentedSyntax` is true if a `.sass` file
117+
// Ensure `indented` if a `.sass` file
119118
if (path.extname(file.path) === '.sass') {
120-
opts.indentedSyntax = true;
119+
opts.syntax = 'indented';
121120
}
122121

123122
// Ensure file's parent directory in the include path
124-
if (opts.includePaths) {
125-
if (typeof opts.includePaths === 'string') {
126-
opts.includePaths = [opts.includePaths];
123+
if (opts.loadPaths) {
124+
if (typeof opts.loadPaths === 'string') {
125+
opts.loadPaths = [opts.loadPaths];
127126
}
128127
} else {
129-
opts.includePaths = [];
128+
opts.loadPaths = [];
130129
}
131130

132-
opts.includePaths.unshift(path.dirname(file.path));
131+
opts.loadPaths.unshift(path.dirname(file.path));
133132

134133
// Generate Source Maps if the source-map plugin is present
135134
if (file.sourceMap) {
136-
opts.sourceMap = file.path;
137-
opts.omitSourceMapUrl = true;
138-
opts.sourceMapContents = true;
135+
opts.sourceMap = true;
136+
opts.sourceMapIncludeSources = true;
139137
}
140138

139+
const fileContents = file.contents.toString();
141140
if (sync !== true) {
142141
/**
143-
* Async Sass render
142+
* Async Sass compile
144143
*/
145-
gulpSass.compiler.render(opts, (error, obj) => {
146-
if (error) {
144+
gulpSass.compiler
145+
.compileStringAsync(fileContents, opts)
146+
.then((compileResult) => {
147+
filePush(file, compileResult, callback);
148+
})
149+
.catch((error) => {
147150
handleError(error, file, callback);
148-
return;
149-
}
150-
151-
filePush(file, obj, callback);
152-
});
151+
});
153152
} else {
154153
/**
155-
* Sync Sass render
154+
* Sync Sass compile
156155
*/
157156
try {
158-
filePush(file, gulpSass.compiler.renderSync(opts), callback);
157+
filePush(file, gulpSass.compiler.compileString(fileContents, opts), callback);
159158
} catch (error) {
160159
handleError(error, file, callback);
161160
}
@@ -164,21 +163,21 @@ const gulpSass = (options, sync) => {
164163
};
165164

166165
/**
167-
* Sync Sass render
166+
* Sync Sass compile
168167
*/
169168
gulpSass.sync = (options) => gulpSass(options, true);
170169

171170
/**
172171
* Log errors nicely
173172
*/
174173
gulpSass.logError = function logError(error) {
175-
const message = new PluginError('sass', error.messageFormatted).toString();
174+
const message = new PluginError('sass', error).toString();
176175
process.stderr.write(`${message}\n`);
177176
this.emit('end');
178177
};
179178

180179
module.exports = (compiler) => {
181-
if (!compiler || !compiler.render) {
180+
if (!compiler || !compiler.compile) {
182181
const message = new PluginError(
183182
PLUGIN_NAME,
184183
MISSING_COMPILER_MESSAGE,

0 commit comments

Comments
 (0)