Skip to content
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

refactor(package): remove node-sass (peerDependencies) #533

Merged
merged 20 commits into from
Apr 12, 2018

Conversation

Timer
Copy link
Contributor

@Timer Timer commented Jan 15, 2018

Fixes #532

Let me know what more is required. Doc changes, fixing coverage, etc.

image

image

image

@jsf-clabot
Copy link

jsf-clabot commented Jan 15, 2018

CLA assistant check
All committers have signed the CLA.

@codecov
Copy link

codecov bot commented Jan 15, 2018

Codecov Report

Merging #533 into master will increase coverage by 0.14%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #533      +/-   ##
==========================================
+ Coverage   97.43%   97.58%   +0.14%     
==========================================
  Files           6        6              
  Lines         117      124       +7     
==========================================
+ Hits          114      121       +7     
  Misses          3        3
Impacted Files Coverage Δ
lib/loader.js 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eb5a555...2cb77d9. Read the comment docs.

lib/loader.js Outdated
const sass = require("node-sass");
const sassVersion = require("node-sass/package.json").version;

if (/^4[.]/.test(sassVersion)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think better to check >= 4, maybe in future we can have 5

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, please check for greater than

if (Number(sassVersion[0]) >= 4) {}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we're not compatible with the node-sass v5 API?

lib/loader.js Outdated
const sass = require("node-sass");
const sassVersion = require("node-sass/package.json").version;

if (/^4[.]/.test(sassVersion)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, please check for greater than

if (Number(sassVersion[0]) >= 4) {}

lib/loader.js Outdated
if (/^4[.]/.test(sassVersion)) {
asyncSassJobQueue = async.queue(sass.render, threadPoolSize - 1);
} else {
loadingError = new Error("The installed version of \`node-sass\` is not compatible (expected: 4.x, actual: " + sassVersion + ").");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw here and catch the {Error} in (L27+) instead of an assignment please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. This will work better when we add support for things other than node-sass or something else bombs out.

@michael-ciniawsky michael-ciniawsky changed the title Remove node-sass peerdep refactor(package): remove node-sass (peerDependencies) Jan 16, 2018
@Timer
Copy link
Contributor Author

Timer commented Jan 16, 2018

Updated with concerns.

@@ -12,7 +11,21 @@ const pify = require("pify");
// fs tasks when running the custom importer code.
// This can be removed as soon as node-sass implements a fix for this.
const threadPoolSize = process.env.UV_THREADPOOL_SIZE || 4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let move this variables before asyncSassJobQueue = async.queue(sass.render, threadPoolSize - 1);, it don't have sense in top of file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I should've thought of this. 😝

lib/loader.js Outdated
@@ -35,6 +49,15 @@ function sassLoader(content) {
throw new Error("Synchronous compilation is not supported anymore. See https://github.com/webpack-contrib/sass-loader/issues/333");
}

if (asyncSassJobQueue == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last note 😄 Seems we can avoid this block, just throw error in catch instead loadingError = e;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safe to throw an error at require-time? I figured you'd want them surfaced as webpack compiler errors -- I'm not sure how this works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Timer Yep, it is not compilation error. It does not make sense because all attempts to compile sass/scss return error in callback. I think better throw error as fast as possible. @michael-ciniawsky what do you think about this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't webpack's bail option cause it to stop on the first? I'm no expert here, just asking questions.

Copy link
Member

@michael-ciniawsky michael-ciniawsky Jan 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think this block is redundant with the try/catch (L13+) and version check, but not 💯 😛

- let loadingError = null;

try {
    const sass = require("node-sass");
    const sassVersion = require("node-sass/package.json").version;

    if (Number(sassVersion[0]) >= 4) {
        // This queue makes sure node-sass leaves one thread available for executing
        // fs tasks when running the custom importer code.
        // This can be removed as soon as node-sass implements a fix for this.
        const threadPoolSize = process.env.UV_THREADPOOL_SIZE || 4;

        asyncSassJobQueue = async.queue(sass.render, threadPoolSize - 1);
+       // Maybe not needed (see comment)       
+       if (asyncSassJobQueue === null) {
+           throw new Error("Please install `node-sass >= 4.x` to use `sass-loader`.")
+       }
    } else {
        throw new Error("The installed version of \`node-sass\` is not compatible (expected: >=4.x, actual: " + sassVersion + ").");
    }
} catch (err) {
+  // Catches 'both' (first thrown) {Error} thrown in the try block 
+   callback(err);

+   return;
}

...

-    if (asyncSassJobQueue == null) {
-        if (loadingError) {
-            callback(loadingError);
-            return;
-        }
-        callback(new Error("Please install `node-sass >=4.x` to use `sass-loader`."));
-        return;
-    }

But what's the exact reason for asyncQueue === null, in case node-sass < 4 ? And isn't this basically a redundant (the same check) as if (Number(sassVersion[0]) >= 4) again ? Please elaborate what could possibly fail when queueing sass.render for thread pooling, since I'm not that familiar with node-sass :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callback isn't available where you've added it, that's where the package itself is being evaluated.

AFAIK, it's generally poor practice to make a require throw an exception, but this might be normal practice in the webpack world.

The loadingError is to store the error until the plugin is used at compile time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops... 😛you're right. What alternatives do we have to make this less confusing and more compact ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll come up with something.

@Timer
Copy link
Contributor Author

Timer commented Jan 17, 2018

@michael-ciniawsky I went ahead and moved the loading of a compiler into its own file and created placeholder logic for expanding beyond one compiler. This keeps the main loader.js clean while allowing it to be extensible going forward.

Let me know what you think!

Copy link
Member

@alexander-akait alexander-akait left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add tests?

@Timer
Copy link
Contributor Author

Timer commented Jan 17, 2018

Can we add tests?

Sure! I just want to make sure the code is accepted and no functionality majorly changes before I write the test cases. 😄

@alexander-akait
Copy link
Member

@michael-ciniawsky friendly ping

@Timer
Copy link
Contributor Author

Timer commented Jan 19, 2018

@michael-ciniawsky could you please see if you agree with the changes? 😄

Copy link
Member

@jhnns jhnns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Timer Thanks for your contribution. I'm willing to merge this since it seems like this could improve the overall flexibility and developer experience. It also helps the maintainers of create-react-app to support Sass out of the box (#532) @gaearon.

This is going into the right direction, but I'm not sure how big the change should be. Currently, this is built with the flexibility in mind to support multiple compilers. However, this is only going to work if all these node packages provide roughly the same API/behavior as node-sass. Could you name some node packages for example so that I can get a better understanding of that requirement?

If a sass compiler/node package exposes a completely different API, it probably makes more sense to have a dedicated loader for it.

So, if there are no other packages that provide the same API, we should probably make the change smaller and just check specifically for node-sass.

Besides, we also have to keep in mind that the current sass-loader implementation applies some fixes that expect a specific node-sass behavior.

What do you think?

.nycrc Outdated
@@ -6,9 +6,9 @@
"include": [
"lib/**/*.js"
],
"lines": 97,
"lines": 92,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should just decrease the coverage limit here 😁
The new code should have tests :). Maybe we should add each supported compiler as dev dependency. Then requiring it in a test should be no problem.

try {
const value = compiler.getCompilerQueue();

if (value == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of these == null checks (the V8 for instance has a hard time optimizing these since document.all == null evaluates to true 😁). Why not check on === null instead? We know that the compiler queue should return null, so let's enforce a strict API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.

}
// Return the error encountered while loading a compiler, otherwise say
// there was no compiler found.
return {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just return the queue here or throw or log the error if none was available?

Copy link
Contributor Author

@Timer Timer Mar 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK throwing on require is being a bad neighbor, so we store the error until the loader is invoked (this function is called synchronously on package evaluation).

@@ -0,0 +1,27 @@
"use strict";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you rename that file to node-sass. The sass-loader doesn't really know about libsass

lib/loader.js Outdated
@@ -35,6 +30,13 @@ function sassLoader(content) {
throw new Error("Synchronous compilation is not supported anymore. See https://github.com/webpack-contrib/sass-loader/issues/333");
}

const compilerError = asyncJobQueue.error;

if (compilerError) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to do that check. If the error was just thrown, webpack would report the loader error accordingly.

@alexander-akait
Copy link
Member

/cc @Timer let's finish this PR and implement dart-sass support

@alexander-akait alexander-akait mentioned this pull request Mar 24, 2018
@Timer
Copy link
Contributor Author

Timer commented Mar 25, 2018

I believe dart-sass support would be better in a PR after this. I toyed with the idea (see tree at d2dae27) but I think it'll require more significant changes (such as the error message massaging and fixing library-specific quirks).

Let's keep this PR focused to removing the peer dep.

@Timer
Copy link
Contributor Author

Timer commented Mar 25, 2018

@jhnns I've greatly simplified this PR and added tests; can I ask for another review?

@Timer
Copy link
Contributor Author

Timer commented Mar 25, 2018

Remaining tests should pass after #514 is merged.

@alexander-akait
Copy link
Member

/cc @michael-ciniawsky

@Timer
Copy link
Contributor Author

Timer commented Apr 10, 2018

Hi! Anything we can do to help this along?

We'd really like to add Sass support in Create React App, but we need this released first.

Copy link
Member

@alexander-akait alexander-akait left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one note 👍

"functions": 100,
"branches": 89,
"branches": 91,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we return old values and add more tests?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @Timer

Copy link
Contributor Author

@Timer Timer Apr 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, you want me to reduce target test coverage and add then add more tests?

I increased the values here, I did not decrease them -- the tests I added provided more coverage than previously available.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Timer oh sorry, all looks good 👍

@jhnns
Copy link
Member

jhnns commented Apr 12, 2018

LGTM 👍 thank you 👏

Travis is failing right now since it's trying to run webpack@4 with node 4 which doesn't work... I'll try to get #514 merged so that our CI is working again.

@jhnns jhnns mentioned this pull request Apr 12, 2018
@jhnns jhnns merged commit 6439cef into webpack-contrib:master Apr 12, 2018
@jhnns
Copy link
Member

jhnns commented Apr 13, 2018

I will release this tomorrow together with #479 #555

@geoffreydhuyvetters
Copy link

this is a massive PR, lots of people will be happy :)

@jhnns
Copy link
Member

jhnns commented Apr 13, 2018

Shipped with sass-loader 7.0.0. There is no peer dependency on node-sass anymore.

@@ -54,7 +55,6 @@
"node": ">= 6.9.0 || >= 8.9.0"
},
"peerDependencies": {
"node-sass": "^4.0.0",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove node-sass as a peerDependency when sass-loader explicitly requires a version?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sass-loader requires either node-sass or sass. There's no way to express that as a peer dependency without having npm complain about one or the other missing.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Thank you. Didn't know you could use either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consider removing peerDependency node-sass and enforcing it at runtime instead
8 participants