Running Dart Sass on Gulp or Grunt - sass

Ruby Sass is going away (unless a new maintainer takes it on) and is being replaced by a Dart implementation, according to this post:
Announcing Dart Sass
Does anyone know if there are plugins already in progress for Gulp or Grunt?

I was working on a personal project several months ago and wanted dart-sass with gulp so I made my own rudimentary function for until someone else came along and made something better. I don't remember which version dart-sass was on at the time, but here's the function anyway. It just sits right in the gulpfile.
function sassify(options) {
return through.obj(function (file, enc, cb) {
options = options || {};
options.file = file.path;
// if (file.sourceMap) {
// options.sourceMap = true;
// options.outFile = output.path('css');
// }
sass.render(options, function (err, result) {
if (err) {
console.error("Sass Error: " + err.message);
}
else {
file.contents = result.buffer;
// if (file.sourceMap) {
// applySourceMap(file, result.map);
// }
}
cb(err, file);
});
});
}
At the time, dart-sass didn't have source maps yet so I just plugged that stuff in and commented it out for when they do.
I used the function this way:
gulp.task('build:css', function () {
gulp.src(input.sass)
// .pipe(sourcemaps.init())
.pipe(sassify())
// .pipe(sourcemaps.write(output.path('cssmap')))
.pipe(concat(output.path('css')))
.pipe(gulp.dest('.'));
});

Using dart-sass from gulp should be straightforward:
https://www.npmjs.com/package/dart-sass#from-npm
npm install dart-sass
var sass = require('dart-sass');
sass.render(...)
Don't know about grunt though.

Since the news of Ruby Sass' deprecation and first official release of Dart Sass, I recently contributed the grunt-dart-sass package to the npm registry, and it looks like another user has contributed gulp-dart-sass. Since these are user-contributed packages, they were not created by the makers of Dart Sass themselves but still interface with the Dart Sass API. Hopefully, the grunt-contrib-sass project will also upgrade their package to use Dart Sass soon enough.

Related

usage of JS plugins with webpack

I am trying to reconfigure my Symfony 3 project to use webpack encore instead of normal asstets. I am a little stuck with this.
For one part of the application I developed some JS plugins which inherits from Kube (a CSS and JS Framework I am unsing). Here is an exmaple:
(function (Kube) {
Kube.Assignment = function (element, options) {
this.namespace = 'assignment';
this.defaults = {
//...
};
Kube.apply(this, arguments);
this.start();
};
Kube.Assignment.prototype = {
start: function () {
//...
}
};
Kube.Assignment.inherits(Kube.Distribution);
Kube.Plugin.create('Assignment');
Kube.Plugin.autoload('Assignment');
}(Kube));
Unfortunatly Kube is not recognized.
The module 'imperavi-kube' is installed via yarn and is imported via
let Kube = require('imperavi-kube');
I am getting the following error: TypeError: Kube.Assignment.inherits is not a function
Propably this is not a issue of the Kube Framework but somthing about handeling JS plugins with webpack.
Inside the Kube module there is a class 'Kube' defined with a prototype. The Prototype ends with window.Kube = Kube;
Try to import Kube like this:
import * as Kube from <your path> or <alias> or <module name>
I may be wrong, but as far as I remember sometimes it works a bit differently.

Getting Webpack 2 to support IE8

I want to use Webpack 2 in a large project which must still support IE8.
I've installed babel-preset-env so I can easily deprecate any IE < 11 in future, one by one, once each of the browsers becomes unsupported by this project.
According to the babel-preset-env readme "If you are targeting IE 8 and Chrome 55 [babel-preset-env] will include all plugins required by IE 8 since you would need to support both still."
As I understand it, I also need to install babel-polyfill mostly for its IE5 shim, but also for its polyfills for ES6 and 7 features that I may wish to use.
However having installed these things, my code still falls over on IE8 (in Browserstack) at the point where Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); is first run. A function I thought was getting 'fixed' by the shims.
Is it not getting shimmed properly? Have I missed out a step?
I had the same problem before and here is what I did to solve.
In es6 features,
a class can define a property with get and set to encapsulate a field.
but it is not woroking on IE8.
because the defineProperty method is not supported see the docs,
so we changed the whole code pattern to like below
let val1;
class className {
methodName() {
this.val2 = 'test';
//code here
}
getVal1() {
return val1;
}
setVal1(_val1) {
val1 = _val1;
}
getVal2() {
return this.val2;
}
setVal2(_val2) {
this.val2 = _val2;
}
}
module.exports = className;
and I recommend that adding 'es3ify' see the link,github es3ify to your webpack build for IE7/8

Problems with defining modules using AMD in Mocha

While writing tests I got bug TypeError: $.extend is not a function on toastr plugin that we are using. It seems that jQuery is not picked up properly, even tho is working normally in browser.
In our main mock file we imported jQuery and bind it to global windows object and it's accessible across whole application (but toastr plugin), even while testing in mocha:
import jsdom from 'jsdom';
import $ from 'jquery';
import chai from 'chai';
import chaiImmutable from 'chai-immutable';
import React from 'react';
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>');
const win = doc.defaultView;
global.document = doc;
global.window = win;
global.expect = chai.expect;
global.$ = $(win);
global.jquery = $(win);
global.jQuery = $(win);
Object.keys(window).forEach((key) => {
if (!(key in global)) {
global[key] = window[key];
}
});
chai.use(chaiImmutable);
So while taking closer look at toastr I noticed this:
; (function (define) {
define(['jquery'], function ($) {
// this function is called on inizialization
function getOptions() {
return $.extend({}, getDefaults(), toastr.options);
}
It takes jquery from node_modules directly and then defines object $ in function scope, that means that it's ignoring window.$ (which is working normally even in here).
Therefore logging $ will return function, and logging $.anyMethodFromjQuery ($.extend) will return undefined.
In the end I tried logging $.prototype, in the browser it will return me jQuery object while in mocha it returns empty object {}
So in the end it define didn't created prototype in mocha environment and I cannot add one line of code $ = window.$; in plugin, since no one should edit a plugin + we are using npm.
Is there any solution for this?
You're running into trouble because you are loading code that should be loaded by JSDom outside of it. While it is possible in some cases to load code in Node and then pass it to the window that JSDom creates, that's a brittle approach, as you've discovered. Whenever I use JSDom for things other than write-and-toss cases, I load every script that would normally be loaded by a browser through JSDom. This avoids running into the issue you ran into. Here's a proof-of-concept based on the code you've shown in the question. You'll see that toastr.getContainer() runs fine, because Toastr has been loaded by JSDom. If you try to use the same code with an import toastr from "toastr" you'll get the same problem you ran into.
import jsdom from 'jsdom';
import $ from 'jquery';
import path from "path";
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>', {
features: {
FetchExternalResources: ["script"],
ProcessExternalResources: ["script"]
}
});
const win = doc.defaultView;
global.document = doc;
global.window = win;
global.$ = $(win);
global.jquery = $(win);
global.jQuery = $(win);
window.addEventListener("error", function () {
console.log("ERROR");
});
const script = document.createElement("script");
script.src = path.join(__dirname, "./node_modules/toastr/toastr.js");
document.head.appendChild(script);
// The load will necessarily be asynchronous, so we have to wait for it.
script.addEventListener("load", function () {
console.log("LOADED");
console.log(window.toastr);
// We do this here so that `toastr` is also picked up.
Object.keys(window).forEach((key) => {
if (!(key in global)) {
global[key] = window[key];
}
});
toastr.getContainer();
});
Note that the code hung when I tried calling toastr.info(...). I took a look at the code of Toastr but it is not clear to me what causes the problem. There are features of browsers that JSDom is unable to emulate. It is possible that Toastr is dependent on such features. In the past, I've sometimes had to switch test suites away from JSDom due to its limitations.

Meteor: Make Meteor.method return a callback

New to Meteor, and I love it so far. I use vzaar.com as video hosting platform, and they have a node.js package/API which I added to my Meteor project with meteorhacks:npm. Everything in the API works great, but when I upload a video, I need to fetch the video ID from the API when successfully uploaded.
Problem:
I need to save the video id returned from the vzaar API after uploading, but since it happens in the future, my code does not wait on the result and just gives me "undefined". Is it possible to make the Meteor.method wait for the response?
Here is my method so far:
Meteor.methods({
vzaar: function (videopath) {
api.uploadAndProcessVideo(videopath, function (statusCode, data) {
console.log("Video ID: " + data.id);
return data.id;
}, {
title: "my video",
profile: 3
});
console.log(videoid);
}
});
And this is how the Meteor.call looks like right now:
Meteor.call("vzaar", "/Uploads/" + fileInfo.name, function (err, message) {
console.log(message);
});
When I call this method, I immediately get undefined in browser console and meteor console, and after some seconds, I get the video ID in the meteor console.
Solution
I finally solved the problem, after days of trial and error. I learned about Fibers (here and here), and learned more about the core event loop of Node.js. The problem were that this call answered in the future, so my code always returned undefined because it ran before the api had answered.
I first tried the Meteor.wrapAsync, which I thought were going to work, as it is actually the Future fiber. But I ended up using the raw NPM module of Future instead. See this working code:
var Future = Npm.require('fibers/future');
Meteor.methods({
vzaar: function (videopath) {
var fut = new Future();
api.uploadAndProcessVideo(videopath, function (statusCode, data) {
// Return video id
fut.return (data.id);
}, {
// Video options
title: "hello world",
profile: 3
});
// The delayed return
return fut.wait();
}
});
Remember to install the npm module correctly with meteorhacks:npm first.
I learned about how to use the Future fiber in this case via this stackoverflow answer.
I hope this can be useful for others, as it was really easy to implement.

How to use SASS in Dart editor

Anyone have a canned solution for integrating SASS or another CSS preprocessor into the Dart editor? Seems to require a custom build.dart, which I would rather copy than code. Thanks.
I stumbled upon this a few days ago
Sass integration for pub
Here is a build.dart file with basic support for SASS:
import 'dart:io';
void main(List<String> args) {
for (String arg in args) {
if (arg.startsWith('--changed=')) {
String file = arg.substring('--changed='.length);
if (file.endsWith('.scss')) {
var result = Process.runSync('sass',
[ '--line-numbers', file,
file.substring(0, file.length - '.scss'.length) + '.css']);
if (result.exitCode != 0) {
// report error (SASS seems to only report first error)
// split error lines
var lines = result.stderr.split('\n');
// escape quotes in error message on first line
var error = lines[0].replaceAll('"', r'\"');
// extract line number from second line
var numMatch = new RegExp(r'\d+').firstMatch(lines[1]);
var lineNum = numMatch == null ? 1 : num.parse(numMatch.group(0));
// Report error via JSON
print('[{"method":"error","params":{"file":"$file","line":$lineNum,"message":"$error"}}]');
}
}
}
}
}
During development (with Dart Editor or another editor...), just use sass the way it's meant to be used, in your directory project :
sass -w .
Put the CSS generated files in the ignore list of your source code management system (aka .gitignore for git).
And for dart2js compilation, use the sass pub package : http://pub.dartlang.org/packages/sass

Resources