Is there any way to set a node-sass configurations file? - sass

I've been searching and found some issues and implementations that seems to be deprecated, though I'm not sure (as I tried to implement them and failed).
If it still not clear, what I want to achieve is a command line like so:
Straight in command line or npm scripts, we'd use something like this:
node-sass --config sassconfig.json
In sassconfig.json, we'd have a code like the one below:
{
"outputStyle": "compressed",
"sourceMap": true
}
This setup would make it more elegant and straightforward, just like tsconfig.json.

Normally you dont render Sass manually with a npm command. Integrate Sass in your webserver and render it when the server starts and your watcher programm recognize changes in the code (nodemon, Webpack hot module, etc.)
Here is an example for an expressJs server:
https://stackoverflow.com/a/26277894/6564085
Let me quote swervos' answer from the link to save the snippet in this answer:
var connect = require('connect');
var sass = require('node-sass');
var srcPath = __dirname + '/sass';
var destPath = __dirname + '/public/styles';
var server = connect.createServer(
sass.middleware({
src: srcPath,
dest: destPath,
debug: true,
outputStyle: 'expanded',
prefix: '/styles'
}),
connect.static(__dirname + '/public')
);
If you want to use Webpack heres a webpack version:
https://stackoverflow.com/a/46059484/6564085
let me quote Arnelle Balane's for it.
{
test: /.scss$/,
use: ExtractTextPlugin.extract({
fallbackLoader: "style-loader",
use: [{
loader: 'css-loader'
}, {
loader: 'sass-loader',
options: {
outputStyle: 'expanded'
}
}]
})
}
More information here: https://www.npmjs.com/package/sass-loader

Related

Webpack and SASS sourcemaps paths issue

I've make a very simple project to ilustrate the problem.
The project structure is:
The contents of webpack.config.js:
var path = require('path');
module.exports = {
entry: [
'./src/main.js',
'./src/main.scss'
],
output: {
path: path.join(__dirname, 'www/'),
filename: 'bundle.js'
},
module: {
loaders: [{
loaders: ['style-loader', 'css-loader?sourceMap', 'sass-loader?sourceMap'],
test: /\.scss$/
}]
},
devtool: 'source-map',
devServer: {
contentBase: 'www/'
}
};
The bundle generation is working properly, but when I debug the application, the SASS sourcemaps don't have the right base path:
Because it nests a second src/ folder in src/. I've tried to add to the sass-loader the sourceMapRoot option:
'sass-loader?sourceMap&sourceMapsRoot=src/'
But it doesn't fix the issue. I know it isn't significant, but I want to know if anyone have it working properly or have the same problem.
Best regards, thank you.

"transform-es3-member-expression-literals" usage in webpack 1.x

I am working on application that needs to be run on IE 8 enterprise version.I am getting following errors in the console:
Expected identifier : ;
indexOf is not available for the object.
For solving this I read this question on stackoverflow:
Babel 6.0.20 Modules feature not work in IE8
It suggests
transform-es3-member-expression-literals
transform-es3-property-literals
to be added.
But using this in webpack is not mentioned any where,not on babel official site.
Can anyone suggest the way how can I use it as a plugin to my project.
Note:I have already tried doing
var es3MemberExpressionLiterals = require('babel-plugin-transform-es3-member-expression-literals');
var es3PropertyLiterals = require('babel-plugin-transform-es3-property-literals');
plugins = [// Plugins for Webpack
new webpack.optimize.UglifyJsPlugin({minimize: false}),
new HtmlWebpackPlugin({
template: 'index.html', // Move the index.html file...
minify: { // Minifying it while it is parsed using the following, self–explanatory options
removeComments: false,
collapseWhitespace: false,
removeRedundantAttributes: false,
useShortDoctype: false,
removeEmptyAttributes: false,
removeStyleLinkTypeAttributes: false,
keepClosingSlash: true,
minifyJS: false,
minifyCSS: true,
minifyURLs: false
}
})
new es3MemberExpressionLiterals(),
new es3PropertyLiterals()
];
I've created a demo repository on github to show the full configuration by an example.
To get the two plugins running create a .babelrc file, with the following content
{
"plugins": [
"transform-es3-member-expression-literals",
"transform-es3-property-literals"
]
}
In the standard configuration babel-loader in your webpack.config.js babel takes a look into the .babelrc to configure plugins.
// webpack.config.js (partial code only)
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
}
If everything is set up correctly webpack should transform the following code
// src/main.js
var foo = { catch: function() {} };
console.log(foo.catch)
into
// bundle.js
/* 0 */
/***/ function(module, exports) {
var foo = { "catch": function () {} };
console.log(foo["catch"]);
/***/ }
See also the examples for the plugins: babel-plugin-transform-es3-property-literals and babel-plugin-transform-es3-member-expression-literals.
The question you link to is about Babel plugins, and you are trying to pass them as Webpack plugins. You'd need to set up Babel as a loader for your application and pass the plugins to that. Merge the following into your Webpack configuration.
module: {
loaders: [{
loader: 'babel',
test: /\.js$/,
exclude: /node_modules/,
plugins: [
'babel-plugin-transform-es3-member-expression-literals',
'babel-plugin-transform-es3-property-literals',
],
}],
},

WebSocket shim error with Webpack

I'm having trouble creating a WebSocket object on a webpack project. When I call new WebSocket("") it appears as though I get back the constructor as opposed to a new object of that constructor. I have a simple web page that does not use webpack and there everything works fine. Stepping through the working version with the Chrome debugger looks like this:
I cannot step into the WebSocket constructor, it just jumps to the next line. Now with my webpacked app it does step into the constructor where I see this:
and upon stepping out I see this:
I'm really not sure what I'm doing wrong here, how can I fix this? The app is not to be hosted by a webpack server, I'm only using webpack for packaging. All of this is on Chrome on OSX; below is my webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
// 'webpack-dev-server/client?http://localhost:3000',
// 'webpack/hot/only-dev-server',
'./src/turborabbit'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
}]
}
};
EDIT:
The module I'm importing and having trouble with is rserve. I have a workaround which is the ugliest thing I have ever done. The module only uses underscore and websocket in the offending file; I have overridden the require call for the module using imports-loader and injected underscore via the ProvidePlugin. This is the relevant portion of webpack config:
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.ProvidePlugin({
'_': 'underscore'
})
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['imports', 'react-hot', 'babel'],
include: path.join(__dirname, 'src')
}]
}
And I load the module as follows:
var Rserve = require ('imports?require=>(function(x){return(x==="ws"?global.WebSocket:_);})!rserve');
I sincerely hope there's a better way
I've found a better solution by aliasing ws in webpack and making a shim that simply returns WebSocket. Relevant portion of webpack.config:
resolve: {
alias: {
ws: path.resolve ('./') + '/src/shim/ws.js'
}
}
and in src/shim/ws.js:
module.exports = WebSocket || MozWebSocket;

Getting Babel 6 to work with IE8 (via. Gulp/Webpack)

I've got Babel 6 working nicely with Gulp and Webpack. I now need to polyfill it to get IE8 support.
I've installed the babel-polyfill, but can't get it working and the docs and Google haven't helped so far.
My Gulp task (inc. Webpack config):
gulp.task('webpack', function(callback) {
var webpackConfig = {
context: __dirname + '../../../js',
entry: {
homepage: [
'babel-polyfill',
'./public/homepage/homepage.js'
]
},
output: {
path: __dirname + '../../../dist/public/scripts/',
filename: '[name].bundle.js'
},
module: {
loaders: [
{
loader: 'babel-loader',
test: /\.js$/, // Only run .js files through Babel
include: /js/, // Only include the /js dir
query: {
//plugins: ['transform-runtime'], // Disabled pending fix to https://github.com/babel/babel/issues/2954
presets: ['es2015'],//, 'stage-0'
}
}
]
}
};
webpack(webpackConfig, function(err, stats) {
if (err) {
throw new gutil.PluginError('webpack', err);
}
gutil.log('[webpack]', stats.toString({
// output options
}));
callback();
});
});
From the docs (https://babeljs.io/docs/usage/polyfill/):
Usage in Node / Browserify / Webpack
To include the polyfill you need to require it at the top of the entry point to > your application.
require("babel-polyfill");
Usage in Browser
Available from the dist/polyfill.js file within a babel-polyfill npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a before it.
NOTE: Do not require this via browserify etc, use babel-polyfill.
I've tried simply adding the polyfill.js file to the top of the page, but IE8 still isn't happy with the compiled code's use of the default keyword.
I've also tried adding the polyfill to the webpack process, as per http://jamesknelson.com/using-es6-in-the-browser-with-babel-6-and-webpack/ and other suggestions from Google
What am I doing wrong?

Grunt - pass filename variable from command line

I am struggling to understand how I can pass a partial filename from the grunt command line, in order to run a task (from an installed grunt module) on a particular file.
What I want to be able to do is configure a series of tasks to take filename parameter from the command line.
I've tried reworking the final example on this page http://chrisawren.com/posts/Advanced-Grunt-tooling but I'm kind of stabbing in the dark a bit. Thought someone would have a quick answer.
Here is my Gruntfile:
module.exports = function (grunt) {
grunt.initConfig({
globalConfig: globalConfig,
uglify: {
js: {
options: {
mangle: true
},
files: {
'js/<%= globalConfig.file %>.min.js': ['js/<%= globalConfig.file %>.js']
}
}
},
});
// Load tasks so we can use them
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('go', 'Runs a task on a specified file', function (fileName){
globalConfig.file = fileName;
grunt.task.run('uglify:js');
});
};
I attempt to run it from the command line like this:
grunt go:app
to target js/app.js
I get this error:
Aborted due to warnings.
roberts-mbp:150212 - Grunt Tasks robthwaites$ grunt go:app
Loading "Gruntfile.js" tasks...ERROR
>> ReferenceError: globalConfig is not defined
Warning: Task "go:app" not found. Use --force to continue.
Thanks
you can use grunt.option.
your grunt register task will look like this.
> grunt.option('fileName'); grunt.registerTask('go', 'Runs a task on a
> specified file', function (){
> grunt.task.run('uglify:js');
> });
your grunt configuration will be
module.exports = function (grunt) {
var fileName=grunt.option('fileName');
grunt.initConfig({
uglify: {
js: {
options: {
mangle: true
},
files: {
'js/fileName.min.js': ['js/fileName.js']
}
}
},
});
command to run the task from terminal:
$ grunt go --fileName='xyzfile'
I the end I was able to accomplish what I wanted like this, but not sure if this is a standard way.
What I was failing to do was declare the globalConfig variable globally first, so that I could redefine it from the Terminal as I ran my grunt task.
Here is an example. When working with HTML emails I need to:
Process my sass files to css (grunt-contrib-sass)
Run an autoprefixer on the resulting css (grunt-autoprefixer)
Minify my CSS and remove CSS comments (grunt-contrib-cssmin)
Include my full CSS in a tag the of my html file (using grunt-include-replace)
Finally, run premailer on the file to inline all styles (grunt-premailer)
The point is, if I am working on several different HTMl emails in the same project, I need to be able to run all these tasks on html files one-by-one, as needed. The Gruntfile below allows me to do this.
What this does:
If you enter into terminal grunt It will simply run the sass task, which processes all sass files - no file parameter needed from Terminal.
However, if I wish to run a series of processes on a single html file, I enter grunt process:fileName with fileName being the name of the html file without the .html extension.
You will notice that the only tasks that require the fileName are actually include-replace and premailer. However, I still want to run al the other CSS cleanup tasks prior to targetting my chosen file.
The key is:
Declaring the global variable
Load the globalConfig variables into the grunt.initConfig
Use the grunt variable declaration where needed in your tasks
register your custom task, with the fileName variable being used as a paramater.
Hope that helps someone.
module.exports = function (grunt) {
var globalConfig = {
file: 'index' // this is the default value, for a single project.
}
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// load the globalConfig variables
globalConfig: globalConfig,
sass: {
dev: {
files: [{
expand: true,
cwd: 'scss',
src: ['*.scss'],
dest: 'css',
ext: '.css'
}]
}
},
cssmin: {
options: {
keepSpecialComments: 0,
keepBreaks: true,
advanced: false
},
target: {
files: [{
expand: true,
cwd: 'css',
src: '*.css',
dest: 'css',
ext: '.css'
}]
}
},
autoprefixer: {
css: {
src: "css/*.css"
}
},
includereplace: {
your_target: {
options: {
prefix: '\\/\\* ',
suffix: ' \\*\\/',
},
files: {
'inline/<%= globalConfig.file %>-inline.html': ['<%= globalConfig.file %>.html']
}
}
},
premailer: {
main: {
options: {
verbose: true,
preserveStyles: true,
},
src: 'inline/<%= globalConfig.file %>-inline.html',
dest: 'inline/<%= globalConfig.file %>-inline.html'
}
},
});
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-include-replace');
grunt.loadNpmTasks('grunt-premailer');
grunt.registerTask('default', 'sass');
grunt.registerTask('process', 'Runs all processing tasks on a specific file to produce inlined file', function (fileName) {
globalConfig.file = fileName;
grunt.task.run('sass', 'autoprefixer', 'cssmin', 'includereplace', 'premailer');
});
}
EDIT: Obviously at the moment this accepts only one parameter I beleive. In other use cases the grunt.option version above could give more functionality, being able to submit several parameters in one command. I will continue to experiment with grunt.option if I find the need to do this.

Resources