Skip to content

util-sass-compiler: update to use dart-sass #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15,994 changes: 15,809 additions & 185 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-unicorn": "^4.0.3",
"jest": "^24.9.0",
"jest-environment-node-single-context": "^27.2.0",
"lerna": "^3.16.4"
},
"jest": {
Expand Down
46 changes: 15 additions & 31 deletions packages/util-sass-compiler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,23 @@ The `render` function returns an Object of the form

### Example

Below is a simple example, see the [test folder](__tests__/unit/lib/js/render.test.js) for more.
Below is a simple example, see the [demo folder](demo/index.js) for more.

```js
import {render} from '@springernature/util-sass-compiler';

describe('Compile Some SASS', () => {
test('CSS String', async () => {
const result = await render({
data: `
$size: 100px;
.foo {
width: $size;
}`;
});
expect(result.css.toString().trim()).toEqual('.foo{width:100px}');
});

test('JSON match', async () => {
const result = await render({
data: `
$size: 100px;
.foo {
width: $size;
}`;
});
expect(result.json).toEqual(
expect.objectContaining({
'.foo': {
'width': '100px'
}
})
);
});
const render = require('@springernature/util-sass-compiler');

// Pass data to compile
await render({
data: `
$size: 100px;
.foo {
width: $size;
}`;
});

// Pass file to compile
await render({
file: 'path/to/file.scss'
});
```

Expand Down
91 changes: 45 additions & 46 deletions packages/util-sass-compiler/__tests__/unit/lib/js/render.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/**
* __tests__/unit/lib/js/render.test.js
* Test: lib/js/render.js
* @jest-environment jest-environment-node-single-context
*/
'use strict';

const path = require('path');
const sass = require('node-sass');
import {render} from '../../../../lib/js/render';
const sass = require('sass');
const render = require('../../../../lib/js/render');

const importsLocation = path.resolve(__dirname, '../scss/imports');

Expand All @@ -24,7 +25,7 @@ const sassData = `
}`;

const functionErrData = `
@import '${importsLocation}';
@use '${importsLocation}';
.foo {
width: half('string');
}`;
Expand All @@ -37,7 +38,7 @@ const functionWarnData = `

// Tests

describe('Compile SASS', () => {
describe('Compile SASS from data', () => {
test('plain CSS from data', async () => {
const result = await render({data: cssData});
expect(result.css.toString().trim()).toEqual('.foo{width:100px}');
Expand All @@ -48,43 +49,15 @@ describe('Compile SASS', () => {
expect(result.css.toString().trim()).toEqual('.foo{width:100px}');
});

test('plain CSS from file', async () => {
const result = await render({
file: path.resolve(__dirname, '../scss/css.css')
});
expect(result.css.toString().trim()).toEqual('.foo{width:100px}');
});

test('SASS from file', async () => {
const result = await render({
file: path.resolve(__dirname, '../scss/nested.scss')
});
expect(result.css.toString().trim()).toEqual('.foo{width:100px}');
});

test('imports don\'t output CSS', async () => {
const result = await render({
file: path.resolve(__dirname, '../scss/_imports.scss')
});
expect(result.css.toString().trim()).toEqual('');
});

test('SASS function', async () => {
const result = await render({
file: path.resolve(__dirname, '../scss/function.scss')
});
expect(result.css.toString().trim()).toEqual('.foo{width:5px}');
});

test('SASS function error', async () => {
return expect(render({data: functionErrData})).rejects.toThrow(
return expect(await render({data: functionErrData})).rejects.toThrow(
'not a number'
)
);
});

test('SASS function warning', async () => {
const mockWarnFunction = jest.fn()
.mockReturnValue(sass.NULL)
.mockReturnValue(sass.NULL);

return render({
data: functionWarnData,
Expand All @@ -93,21 +66,14 @@ describe('Compile SASS', () => {
}
}).then(() => {
return expect(mockWarnFunction.mock.calls[0][0].getValue())
.toEqual('non-whole number 9px')
})
});

test('SASS mixin', async () => {
const result = await render({
file: path.resolve(__dirname, '../scss/mixin.scss')
.toEqual('non-whole number 9px');
});
expect(result.css.toString().trim()).toEqual('.foo{background-color:blue;border:1px solid red;padding:10px}');
});

test('no data or file provided', async () => {
return expect(render()).rejects.toThrow(
'No input specified: provide a file name or a source string to process'
)
);
});

// Check returned data as JSON
Expand All @@ -117,7 +83,7 @@ describe('Compile SASS', () => {
expect(result.json).toEqual(
expect.objectContaining({
'.foo': {
'width': '100px'
width: '100px'
}
})
);
Expand All @@ -128,9 +94,42 @@ describe('Compile SASS', () => {
expect(result.json).toEqual(
{
'.foo': {
'width': '100px'
width: '100px'
}
}
);
});
});

describe('Compile SASS from file', () => {
test('plain CSS from file', async () => {
const result = await render({file: path.resolve(__dirname, '../scss/css.css')});
expect(result.css.toString().trim()).toEqual('.foo{width:100px}');
});

test('SASS from file', async () => {
const result = await render({file: path.resolve(__dirname, '../scss/nested.scss')});
expect(result.css.toString().trim()).toEqual('.foo{width:100px}');
});

test('imports don\'t output CSS', async () => {
const result = await render({file: path.resolve(__dirname, '../scss/_imports.scss')});
expect(result.css.toString().trim()).toEqual('');
});

test('SASS function', async () => {
const result = await render({file: path.resolve(__dirname, '../scss/function.scss')});
expect(result.css.toString().trim()).toEqual('.foo{width:5px}');
});

test('SASS mixin', async () => {
const result = await render({file: path.resolve(__dirname, '../scss/mixin.scss')});
expect(result.css.toString().trim()).toEqual('.foo{background-color:blue;border:1px solid red;padding:10px}');
});

test('no data or file provided', async () => {
return expect(render()).rejects.toThrow(
'No input specified: provide a file name or a source string to process'
);
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@use "sass:math";

@function half($number) {
@if not (type-of($number) == 'number') {
@error 'not a number';
Expand All @@ -7,7 +9,7 @@
@warn 'non-whole number #{$number}';
}

@return $number / 2;
@return math.div($number, 2);
}

@mixin box {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@import './imports';
@use './imports';

.foo {
width: half(10px);
width: imports.half(10px);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@import './imports';
@use './imports';

.foo {
@include box;
@include imports.box;
}
29 changes: 29 additions & 0 deletions packages/util-sass-compiler/demo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'strict';

const path = require('path');
const render = require('../lib/js/render');

const sassData = `
$width: 100px;
.foo {
width: $width;
}`;

(async () => {
try {
const results = {
data: await render({data: sassData}),
css: await render({file: path.resolve(__dirname, '../__tests__/unit/lib/scss/css.css')}),
mixin: await render({file: path.resolve(__dirname, '../__tests__/unit/lib/scss/mixin.scss')}),
function: await render({file: path.resolve(__dirname, '../__tests__/unit/lib/scss/function.scss')})
};

for (const key in results) {
if (Object.prototype.hasOwnProperty.call(results, key)) {
console.log(`${key}: ${results[key].css}`);
}
}
} catch (error) {
throw new Error(error.message);
}
})();
36 changes: 21 additions & 15 deletions packages/util-sass-compiler/lib/js/render.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
/**
* render.js
* Promisify SASS.render and add JSON output
* compile SASS and convert to JSON
*/
'use strict';

const util = require('util');

const css2json = require('css2json');
const sass = require('node-sass');
const sass = require('sass');

const sassRender = util.promisify(sass.render);
// Using a compact/compressed output style allows you to use concise 'expected' CSS
const defaultOpts = {
style: 'compressed'
};

/**
* Generate a compiled SASS object
* @param {Object} options node sass options
* @return {Object}
*/
module.exports.render = async options => {
module.exports = async (options = {}) => {
let sassObject;
const opts = Object.assign(defaultOpts, options);

try {
const sassObject = await sassRender({
// Where node-sass should look for files when you use @import
includePaths: [__dirname],
// Using a compact/compressed output style allows you to use concise 'expected' CSS
outputStyle: 'compressed',
// Merge in any other options you pass when calling render
// Should include `file` or `data`
...options
});
if (typeof options.data === 'undefined' && typeof options.file === 'undefined') {
throw new TypeError('Expects Object.data or Object.file in arguments');
}

if (options.data) {
sassObject = sass.compileString(options.data, opts);
}

if (options.file) {
sassObject = sass.compile(options.file, opts);
}

// Return SASS object including JSON variant
return {
Expand Down
2 changes: 1 addition & 1 deletion packages/util-sass-compiler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"homepage": "https://github.com/springernature/frontend-toolkit-utilities/tree/master/packages/util-sass-compiler#readme",
"dependencies": {
"css2json": "^1.1.1",
"node-sass": "^4.14.1"
"sass": "^1.47.0"
}
}