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

Stripping out inline source maps #1

Closed
andrewjmead opened this issue Sep 9, 2014 · 45 comments
Closed

Stripping out inline source maps #1

andrewjmead opened this issue Sep 9, 2014 · 45 comments

Comments

@andrewjmead
Copy link

I though it was an issue with gulp-sass, but it turns out that gulp-autoprefixer was the culprit.

Problematic Task

gulp.task('css:dev', function () {
    return gulp.src('public/css/core.scss')
        .pipe(sass({sourceComments: 'map', errLogToConsole: true}))
        .pipe(autoprefix())
        .pipe(gulp.dest('public/css/'));
});

Issue

After the scss is compiled into css, it has inline source maps that look like the following

/*# sourceMappingURL=data:application/json;base64,[base64 data]*/

Once that file is run through autoprefixer, the source maps don't exist. I wasn't able to find any documenation

@battaglr
Copy link

battaglr commented Sep 9, 2014

Can you please confirm that the version you are using is the v1?

@andrewjmead
Copy link
Author

Yes, I'm on 1.0.0. I found the problematic line:

res = autoprefixer(fileOpts).process(file.contents.toString(), {
    map: file.sourceMap ? {annotation: false} : false, // ***** causing the issue
    from: file.relative,
    to: file.relative
});

postcss/autoprefixer readme.md - Autoprefixer supports inline source maps too.

It seems like everything should work, but it's removing the css source map comment entirely.

@battaglr battaglr added the bug label Sep 9, 2014
@andrewjmead
Copy link
Author

I just discovered an inline option that postcss/autoprefixer-core has:

res = autoprefixer(fileOpts).process(file.contents.toString(), {
    map: {inline: true}, // let users of gulp-autoprefixer set some options
    from: file.relative,
    to: file.relative
 });

This adds support for inline maps. Is this configuration exposed to users of gulp-autoprefixer?

@sindresorhus
Copy link
Owner

As mentioned in the readme gulp-sourcemaps is the blessed way to do source maps in gulp. You shouldn't have to mess around with individual plugins source map settings.

@battaglr battaglr removed the bug label Sep 9, 2014
@andrewjmead
Copy link
Author

Hmmm, I'll give that another shot. I tried to setup source maps with gulp-sourcemaps but was not able to successfully do so.

@andrewjmead
Copy link
Author

https://github.com/floridoo/gulp-sourcemaps does not support sass/scss at the moment. I opened an issue with them, but I still with the source maps configs were exposed via this plugin.

@andrewjmead
Copy link
Author

My Solution

gulp-sass seems to only support inline source maps. When I switch to gulp-ruby-sass, everything started to work well.

For the record, here is the final working task:

gulp.task('css:dev', function () {
    return gulp.src('public/css/core.scss')
        .pipe(sass({sourcemap: true, sourcemapPath: '../scss'}))
        .on('error', function (error) {
            console.error(error);
            this.emit('end');
        })
        .pipe(sourcemaps.init({loadMaps: true}))
        .pipe(autoprefix({
            browsers: ['last 2 versions']
        }))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('public/build/css/'))
        .pipe(livereload({auto: false}));
});

@sindresorhus
Copy link
Owner

@koistya
Copy link

koistya commented Sep 11, 2014

After upgrading to gulp-autoprefixer v1.0.0:

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

gulp.task('styles', function () {
    return gulp.src('src/styles/bootstrap.less')
        .pipe($.sourcemaps.init())
        .pipe($.less())
        .pipe($.autoprefixer())
        .pipe($.sourcemaps.write())
        .pipe(gulp.dest('./build/css'));
});
$ gulp styles
[09:58:04] Using gulpfile .\gulpfile.js
[09:58:04] Starting 'styles'...

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, or the source map's "file" property. Both were omitted.
    at SourceMapGenerator_applySourceMap [as applySourceMap] (.\node_modules\gulp-autoprefixer\node_modules\vinyl-sourcemaps-apply\node_modules\source-map\lib\source-map\source-map-generator.js:171:17)
    at applySourceMap (.\node_modules\gulp-autoprefixer\node_modules\vinyl-sourcemaps-apply\index.js:11:15)
    at DestroyableTransform._transform (.\node_modules\gulp-autoprefixer\index.js:35:5)
    at DestroyableTransform.Transform._read (.\node_modules\gulp-autoprefixer\node_modules\through2\node_modules\readable-stream\lib\_stream_transform.js:184:10)
    at DestroyableTransform.Transform._write (.\node_modules\gulp-autoprefixer\node_modules\through2\node_modules\readable-stream\lib\_stream_transform.js:172:12)
    at doWrite (.\node_modules\gulp-autoprefixer\node_modules\through2\node_modules\readable-stream\lib\_stream_writable.js:237:10)
    at writeOrBuffer (.\node_modules\gulp-autoprefixer\node_modules\through2\node_modules\readable-stream\lib\_stream_writable.js:227:5)
    at DestroyableTransform.Writable.write (.\node_modules\gulp-autoprefixer\node_modules\through2\node_modules\readable-stream\lib\_stream_writable.js:194:11)
    at write (.\node_modules\gulp-less\node_modules\through2\node_modules\readable-stream\lib\_stream_readable.js:605:24)
    at flow (.\node_modules\gulp-less\node_modules\through2\node_modules\readable-stream\lib\_stream_readable.js:614:7)

Any ideas on how to fix it?

@anthonyhastings
Copy link

I'm having the same problems as @andrewjmead. When I run my SCSS files through gulp-ruby-sass and then through the autoprefixer, a map file is indeed being generated, but not being referenced in the compiled CSS file. It still has an inline sourcemap. My task is as follows:

return gulp.src('./css/src/*.scss')
    .pipe(plumber())
    .pipe(sass({
        noCache: false,
        sourcemap: true,
        style: 'compact'
        sourcemapPath: './src'
    }))
    .pipe(sourcemaps.init({
        loadMaps: true
    }))
    .pipe(autoprefixer({
        browsers: ["last 2 versions", "> 1%", "ie 8", "ie 7"],
        cascade: false
    }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('./css/'));

@andrewjmead
Copy link
Author

@antwan1986 Are you sure that sourcemapPath is correct?

@anthonyhastings
Copy link

If I've read the sourcemapPath documentation correctly:

A relative path from the output CSS directory to the Sass source directory as seen by your web server.

My folder structure is as follows:

/gulpfile.js
/css/build.css
/css/src/build.scss

My sourcemapPath in this instance would be correct, no? from /css to /css/src/?

@andrewjmead
Copy link
Author

@antwan1986 Your sourcemapPath would be correct then. Can you try copying the rest of my task and seeing if that helps? Our look identical (and mine works) except for a few plugin options.

@fixmysync
Copy link

I'm having the same problem as @antwan1986 - I would like to use the external sourcemap but autoprefixer keeps overwriting the /*# sourceMappingURL=css.map */ if I follow the docs for gulp-autoprefixer, gulp-ruby-sass and gulp-sourcemaps.

@andrewjmead I tried your set up, but that gave me inline sourcemaps.

This is the closest I've got to getting it right, but a second map called styles.css.map.map is being generated.

This is my gulpfile:

 // Load Plugins
var gulp = require('gulp');
var Combine = require('stream-combiner');
var plugins = require('gulp-load-plugins')({ camelize: true });
var lr = require('tiny-lr');
var server = lr();
var sourcemaps = require('gulp-sourcemaps');
var sass = require('gulp-ruby-sass');

// Styles Task
gulp.task('styles', function() {
    return gulp.src('library/scss/source/*.scss')
        .pipe(sass({style: 'compact', compass: true}))
        .pipe(sourcemaps.init({loadMaps: true}))
        .pipe(plugins.autoprefixer('last 2 versions', 'ie 9', 'ios 6', 'android 4'))
        .pipe(sourcemaps.write('../scss/source/', {addComment: true}))
        .pipe(plugins.livereload(server))
        .pipe(gulp.dest('library/css'))
        .pipe(plugins.notify({ message: 'The styles tasks are done!' }));
}); 

// more tasks here

gulp.task('default', ['styles', 'plugins', 'scripts', 'watch']);

And this is what node has to say when I run gulp styles

Using gulpfile ~/path-to-my-file/gulpfile.js
[00:53:22] Starting 'styles'...
[00:53:22] gulp-ruby-sass: directory
[00:53:33] gulp-ruby-sass: write style.css
  write style.css.map
[00:53:34] style.css.map was reloaded.
[00:53:34] style.css was reloaded.
[00:53:34] style.css.map.map was reloaded.
[00:53:34] style.css.map was reloaded.
[00:53:34] Live reload server listening on: 35729
[00:53:34] gulp-notify: [Gulp notification] The styles tasks are done!
[00:53:35] gulp-notify: [Gulp notification] The styles tasks are done!
[00:53:35] gulp-notify: [Gulp notification] The styles tasks are done!
[00:53:35] gulp-notify: [Gulp notification] The styles tasks are done!
[00:53:35] Finished 'styles' after 14 s

I've tried moving .pipe(sourcemaps.init({loadMaps: true})) to after autoprefixer and I've also tried putting .pipe(sourcemaps.init()) there instead - none of these options work.

@andrewjmead
Copy link
Author

@MandyMadeThis I was unable to find a working combination aside from the one I posted 😦

@anthonyhastings
Copy link

Just retried your suggestions myself @andrewjmead, the sourcemap stays inline for me :(

@andrewjmead
Copy link
Author

Yeah, you might have to use inline maps (I have to). Are they not working or is there some other reason why you need external source maps?

@anthonyhastings
Copy link

I need them to be external for my production environments. I find them useful to have on production servers for easier debugging, however, the source map size can be considerable and there's no point in putting that extra weight onto the client / customer if they'll never use it themselves.

@andrewjmead
Copy link
Author

As mentioned in the readme gulp-sourcemaps is the blessed way to do source maps in gulp. You shouldn't have to mess around with individual plugins source map settings.

@sindresorhus I agree. The issue is that the two main SASS gulp tasks, gulp-sass, and gulp-ruby-sass have their own sourcemap settings. There is not good way to get all the plugins to work together.

@andrewjmead
Copy link
Author

@antwan1986 Here is a good solution for external sourcemaps.

Gulp-sass only generates inline sourcemaps, but you can load those in with gulp-sourcemaps, then save them as external sourcemaps with no extra files or strange things. Most of the problems I had came form open issues with gulp-ruby-sass.

gulp.task('sass:main', function () {
    return gulp.src('theme/scss/styles.scss')
        .pipe(sass({sourceComments: 'map'}))
        .on('error', function (error) {
            console.error(error);
            this.emit('end');
        })
        .pipe(sourcemaps.init({loadMaps: true}))
        .pipe(autoprefix({
            browsers: ['last 2 versions']
        }))
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest('./theme/css'));
});

@fixmysync
Copy link

@andrewjmead - will this solution strip the inline sourcemap from the CSS file after the task runs? Or will you have both an external .map file and an inline soucemap?

@andrewjmead
Copy link
Author

@MandyMadeThis I should have clarified 😄. This solution starts with an inline sourcemap (all gulp-sass supports). Then the sourcemaps are loaded in and saved as external sourcemaps. The internal sourcemap is removed, and is replaced by a reference to the external sourcemap.

In the end, you have a css file with a path reference to an external sourcemap 😄!

@jaidetree
Copy link

@andrewjmead I am trying your solution but once autoprefix() is run, the sourcemap gets removed from the gulp-sass buffer and sourcemaps.write() doesn't load anything.

Resulting in a gulp-sourcemap-write: source file not found:<file path>. However if I remove autoprefix, it generates the correct sourcemap but then I'm lacking any of the prefixed css.

gulp.task('sass', function () {
  gulp.src(dir('static/sass/**/*.scss'))
    .pipe(sass({
      sourceComments: 'map',
      includePaths: [dir('static/sass')]
    }))
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(autoprefix({
      browsers: ['last 2 versions']
    }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest(dir('static/css')))
    .pipe(reload({ stream: true }));
});

@aaronjensen
Copy link

@jayzawrotny this is more complicated (as it includes prepending some vendor css) and working for me (pardon the coffee)

gulp = require('gulp')
autoprefixer = require('gulp-autoprefixer')
sass = require('gulp-sass')
reload = require('browser-sync').reload
sourcemaps = require('gulp-sourcemaps')
filter = require('gulp-filter')
merge = require('merge-stream')
concat = require('gulp-concat')

gulp.task('css', ->
  vendor = gulp.src([
    'node_modules/normalize.css/normalize.css'
  ])

  main = gulp.src(['app/assets/css/main.sass'])
    .pipe(sourcemaps.init())
    .pipe(sass())
    .pipe(sourcemaps.write())

    .pipe(sourcemaps.init(loadMaps: true))
    .pipe(autoprefixer())
    .pipe(sourcemaps.write())

  merge(vendor, main)
    .pipe(sourcemaps.init(loadMaps: true))
    .pipe(concat("main.css"))
    .pipe(sourcemaps.write('./'))

    .pipe(gulp.dest('public/css'))

    .pipe(filter('**/*.css'))
    .pipe(reload(stream: true))
)

@valdelama
Copy link

I am having the same issue as @jayzawrotny, this works fine:

var startSassTask = lazypipe()
  .pipe(sourcemaps.init)
  .pipe(sass)
  //.pipe(prefix)
  .pipe(sourcemaps.write);

and as soon as I uncomment the .pipe(prefix) (which is using gulp-autoprefixer) then I get the error message:
gulp-sourcemap-write: source file not found: [path trying to find a css file but pointing at my sass dir]

@aaronjensen I think your solution only works if your src is a single file, not a glob

@andrewjmead
Copy link
Author

@valdelama I did a quick write up of my solution (it's also posted above): http://www.devworkflows.com/posts/getting-scss-auto-prefixer-and-source-map-to-play-nice/

@valdelama
Copy link

@andrewjmead Thanks, I tried your solution and it did create a .map file but it wasn't recognised in chrome dev tools, or at least I couldn't see the .scss source files. If I use my code from above (with autoprefixer commented out) then I have inline sourcemaps that are picked up by chrome automatically. Also from what I can tell from the documentation it is now recommended to not use the gulp-sass built in sourcemaps and instead use gulp-sourcemaps for all plugins.

@andrewjmead
Copy link
Author

@valdelama I'm with you. The issue is that the gulp plugin (in this case gulp-sass) needs to explicitly support gulp-sourcemaps. If plugin developers do support gulp-sourcemaps, awesome, but it's not supported automatically.

If the .map file is generated, but it's not showing, there is a chance that it's invalid or that you don't have the chrome dev tools properly setup.

@valdelama
Copy link

@andrewjmead gulp-sass does support it now, that's why if you check my code above you will see that this works fine (using gulp-sourcemaps):

var startSassTask = lazypipe()
  .pipe(sourcemaps.init)
  .pipe(sass)
  //.pipe(prefix)
  .pipe(sourcemaps.write);

but as soon as I uncomment the line calling gulp-autoprefixer then I get the gulp-sourcemap-write: source file not found error which is what lead me to believe this is a problem with gulp-autoprefixer and not gulp-sass

@aaronjensen
Copy link

@valdelama that does not work. This does: #1 (comment)

@aaronjensen
Copy link

I believe the problem is w/ autoprefixer, they either dont' support gulp-sourcemaps properly or something else, but what I have in the comment works as a workaround

@aaronjensen
Copy link

@andrewjmead you may consider updating your post now that gulp-sass properly supports gulp-sourcemaps:

gulp.task('sass:custom', function () {
    return gulp.src('theme/scss/styles.scss')
        .pipe(sourcemaps.init())

        // Convert sass into css
        .pipe(sass())

        // Catch any SCSS errors and prevent them from crashing gulp
        .on('error', function (error) {
            console.error(error);
            this.emit('end');
        })

        .pipe(sourcemaps.write())

        // Load existing internal sourcemap
        .pipe(sourcemaps.init({loadMaps: true}))

        // Autoprefix properties
        .pipe(autoprefixer({
            browsers: ['last 2 versions']
        }))

        // Write final .map file
        .pipe(sourcemaps.write('./'))

        // Save the CSS
        .pipe(gulp.dest('./theme/css'));
});

@andrewjmead
Copy link
Author

@aaronjensen I will 😄

@valdelama
Copy link

@aaronjensen @andrewjmead I did try that method as well and I get a different kind of error, like this:
"/vendor/assets/stylesheets/prism.scss" is not in the SourceMap.
basically it errors on the first src file in the main .scss file (which is not an issue when I leave autoprefixer out of it)

@andrewjmead
Copy link
Author

Cool, maybe my method broke with the latest gulp-sass update. I'll check it out.

@aaronjensen
Copy link

@valdelama you've got latest gulp-autoprefixer and gulp-sass? could you paste the entire task?

@valdelama
Copy link

@aaronjensen Package versions:

"gulp-autoprefixer": "^1.0.1",
"gulp-sass": "^1.0",
"gulp-sourcemaps": "^1.2.2"

Pasting the complete tasks is kind of difficult because it's broken up into multiple small reusable parts via lazy pipes but here's the relevant code:

var startSassTask = lazypipe()
  .pipe(sourcemaps.init)
    .pipe(sass, {
      errLogToConsole: true,
      includePaths: [vendorAssets.styles, bowerAssets, wegoAssets.styles, gemAssets],
      imagePath: '/images'
    })
    .pipe(sourcemaps.write)
    .pipe(sourcemaps.init, {loadMaps: true})
    .pipe(prefix)
  .pipe(sourcemaps.write, './');

var sassDevTask = startSassTask
  .pipe(gulp.dest, publicAssets)
  .pipe(browserSync.reload, {stream:true});

gulp.task('publicCss', function() {
  return gulp.src('./' + appAssets.styles + '/public_pages.scss',
                  './' + appAssets.styles + '/public_pages_ie8.scss')
    .pipe(sassDevTask());
});

It's part of a pretty large gulp file to replace the rails asset pipeline.

Am I right in thinking that the way this should work in an ideal world is like this (simplified demo):

gulp.src('./scss/*.scss')
  .pipe(sourcemaps.init())
    .pipe(sass())
    .pipe(autoprefixer())
  .pipe(sourcemaps.write())
  .pipe('./css');

?

@aaronjensen
Copy link

@valdelama looks like it's the same as mine, more or less. The only difference is I'm only passing one file through, perhaps that makes a difference in this house of cards :/

I believe what you pasted is how it should work, but it sounds like the problem is not w/ gulp-autoprefixer (according to #8).

@fixmysync
Copy link

I needed to use gulp-ruby-sass because my project is also using compass and gulp-sass does not support compass. So I came up with a solution and it's working beautifully.
I've got a development styles task that gives me external sourcemaps and a production styles task that autoprefixes everything for me - I don't need both in development, so this solution works great for me.

Here is what it looks like:

 var gulp = require('gulp');
 var plugins = require('gulp-load-plugins')({ camelize: true });
 var livereload = require('gulp-livereload');

 // errors function
 function errorLog (error) {
     console.error.bind(error);
     this.emit('end');
 }

 // Development Styles Task
 gulp.task('devStyles', function() {
      return gulp.src('library/scss/main.scss')
          .pipe(plugins.rubySass({ style: 'compact', compass: true }))
          .on('error',errorLog)
          .pipe(gulp.dest('library/css'))
          .pipe(livereload())
          .pipe(plugins.notify({ message: 'The dev styles are done!' }));
 })

 // Production Styles Task
 gulp.task('prodStyles', function() {
      return gulp.src('library/scss/main.scss')
         .pipe(plugins.rubySass({ style: 'compressed', compass: true }))
         .on('error',errorLog)
         .pipe(plugins.autoprefixer( '> 1%', 'last 2 versions', 'ie 9', 'ios 6', 'android 4'))
         .pipe(gulp.dest('library/css'))
         .pipe(plugins.notify({ message: 'The production styles are done' }));
   });

  // A bunch more tasks here

  // Multiple Gulp Tasks
 // run: gulp for default tasks
 gulp.task('default', ['devStyles', 'vendor', 'scripts', 'watch']);

 // run: 'gulp build' for production tasks
 gulp.task('build', ['prodStyles', 'vendor', 'scripts']);

@andrewjmead
Copy link
Author

@aaronjensen I'm unable to get gulp-sass to work with gulp-sourcemaps. I'm getting bad map files and duplicate map files: http://cl.ly/image/312o373X432e

The core.css.map file also does not work.

@aaronjensen
Copy link

@andrewjmead i'm not sure how the collabs feel about this becoming the sass/autoprefixer sourcemaps support thread, but maybe you could put your gulp task in here, it sounds like maybe you're writing to a file twice write('./') rather than writing inline write()

@andrewjmead
Copy link
Author

@aaronjensen Sorry, I just copied your example 😄. My old way still works, so I'm just going to keep using that.

@valdelama
Copy link

@aaronjensen @andrewjmead Just FYI, based on this comment I got it kind of working. Working as in I have sourcemaps and they lead me to the right file via dev tools however line numbers are wrong (as the original commentor mentions) and I still get the source file not found warning.
I also updated gulp-sass to 1.1.0 and gulp-sourcemaps to 1.2.4 which might have helped.
This is the code I'm using (with lazypipes):

var startSassTask = lazypipe()
  .pipe(sourcemaps.init)
    .pipe(sass, {
      errLogToConsole: true,
      includePaths: [vendorAssets.styles, bowerAssets.styles, wegoAssets.styles, gemAssets.styles],
      imagePath: (isDev ? '/images' : '/assets')
    })
  .pipe(sourcemaps.write, {includeContent: false})
  .pipe(sourcemaps.init, {loadMaps: true})
    .pipe(prefix, {cascade: false})
  .pipe(sourcemaps.write);

@polarathene
Copy link

Pretty sure the issue is related to libsass outputting an incorrect sourcemap, autoprefixer runs fine when provided a proper sourcemap. Check that without autoprefixer that your sourcemap in devtools maps to the correct line in .scss, in my case it was either null or the last line of the file. It'll be fixed with libsass 3.2, more info here

@polarathene
Copy link

@andrewjmead @aaronjensen @antwan1986 @valdelama There was an update to gulp-sass today, it supports the v2 beta of node-sass and in turn libsass 3.1-beta. The fixed mappings and bugfixes should solve this issue.

I've provided code examples that worked for me for inline and external sourcemaps with embedded or external sources. You can see them here.

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

No branches or pull requests

10 participants