gulp-sourcemaps / vinyl-sourcemaps-apply

Helper for implementing source map support in Gulp plugins
19 stars 8 forks source link

"/some/thing.scss" is not in the SourceMap #11

Open kilianc opened 8 years ago

kilianc commented 8 years ago

I am not sure what's going on but when I use node-sass and I try to apply a map on multiple steps it starts to throw errors on file paths.

{
  "version":3,
  "sources":[
    "shared.scss",
    "_variables.scss",
    "../../node_modules/bourbon/app/assets/stylesheets/css3/_font-face.scss",
    "../../node_modules/bourbon/app/assets/stylesheets/helpers/_font-source-declaration.scss"
  ],
  "names":[

  ],
  "mappings":"...",
  "file":"bundle.min.css",
  "sourcesContent":[
    "...",
    "...",
    "@mixin font-face(\n  $font-family,\n  $file-path,\n  $weight: normal,\n  $style: normal,\n  $asset-pipeline: $asset-pipeline,\n  $file-formats: eot woff2 woff ttf svg) {\n\n  $font-url-prefix: font-url-prefixer($asset-pipeline);\n\n  @font-face {\n    font-family: $font-family;\n    font-style: $style;\n    font-weight: $weight;\n\n    src: font-source-declaration(\n      $font-family,\n      $file-path,\n      $asset-pipeline,\n      $file-formats,\n      $font-url-prefix\n    );\n  }\n}\n",
    "// Used for creating the source string for fonts using @font-face\n// Reference: http://goo.gl/Ru1bKP\n\n@function font-url-prefixer($asset-pipeline) {\n  @if $asset-pipeline == true {\n    @return font-url;\n  } @else {\n    @return url;\n  }\n}\n\n@function font-source-declaration(\n  $font-family,\n  $file-path,\n  $asset-pipeline,\n  $file-formats,\n  $font-url) {\n\n  $src: ();\n\n  $formats-map: (\n    eot:   \"#{$file-path}.eot?#iefix\" format(\"embedded-opentype\"),\n    woff2: \"#{$file-path}.woff2\" format(\"woff2\"),\n    woff:  \"#{$file-path}.woff\" format(\"woff\"),\n    ttf:   \"#{$file-path}.ttf\" format(\"truetype\"),\n    svg:   \"#{$file-path}.svg##{$font-family}\" format(\"svg\")\n  );\n\n  @each $key, $values in $formats-map {\n    @if contains($file-formats, $key) {\n      $file-path: nth($values, 1);\n      $font-format: nth($values, 2);\n\n      @if $asset-pipeline == true {\n        $src: append($src, font-url($file-path) $font-format, comma);\n      } @else {\n        $src: append($src, url($file-path) $font-format, comma);\n      }\n    }\n  }\n\n  @return $src;\n}\n"
  ],
  "sourceRoot":"/source/"
}

I get:

Error: "/node_modules/bourbon/app/assets/stylesheets/css3/_font-face.scss" is not in the SourceMap.
    at SourceMapConsumer_sourceContentFor [as sourceContentFor] (/Volumes/WS/archive/.../webapp/node_modules/source-map/lib/source-map-consumer.js:703:15)
    at SourceMapGenerator.<anonymous> (/Volumes/WS/archive/.../webapp/node_modules/source-map/lib/source-map-generator.js:229:42)
    at Array.forEach (native)
    at SourceMapGenerator_applySourceMap [as applySourceMap] (/Volumes/WS/archive/.../webapp/node_modules/source-map/lib/source-map-generator.js:228:34)
    at applySourceMap (/Volumes/WS/archive/.../webapp/node_modules/vinyl-sourcemaps-apply/index.js:27:15)
    at Transform.<anonymous> (/Volumes/WS/archive/.../webapp/node_modules/gulp-cssnano/index.js:29:21)
    at process._tickCallback (internal/process/next_tick.js:103:7)

when I run

gulp.task('css', () => {
  return gulp.src([
    'app/styles/shared.scss',
    'app/containers/**/**.scss',
    'app/components/**/**.scss'
  ])
    .pipe(plugins.sourcemaps.init({ loadMaps: true }))
    .pipe(plugins.sass({ includePaths: bourbon.includePaths }))
    .pipe(plugins.concat('bundle.min.css'))
    .pipe(plugins.sourcemaps.write('.'))
    .pipe(gulp.dest('app'))
})

gulp.task('minify:css', () => {
  return gulp.src('app/bundle.min.css')
    .pipe(plugins.sourcemaps.init({ loadMaps: true }))
    .pipe(plugins.cssnano())
    .pipe(plugins.sourcemaps.write('.'))
    .pipe(gulp.dest('dist'))
})

and the failing line is: https://github.com/ben-eb/gulp-cssnano/blob/master/index.js#L29

kilianc commented 8 years ago

If I change one of the files and comment out some of the imports some of the files get resolved with a different path:

{
  "version":3,
  "sources":[
    "shared.scss",
    "../styles/_variables.scss",
    "../styles/_mixins.scss"
  ],
  "names":[

  ],
  "mappings":"...",
  "file":"bundle.min.css",
  "sourcesContent":[
    "...",
    "...",
    "...",
    "...",
    "...",
    "...",
    "...",
    "..."
  ],
  "sourceRoot":"/source/"
}

and it yields

events.js:154
      throw er; // Unhandled 'error' event
      ^
Error: "/styles/_variables.scss" is not in the SourceMap.
    at SourceMapConsumer_sourceContentFor [as sourceContentFor] (/Volumes/WS/archive/.../webapp/node_modules/source-map/lib/source-map-consumer.js:703:15)
    at SourceMapGenerator.<anonymous> (/Volumes/WS/archive/.../webapp/node_modules/source-map/lib/source-map-generator.js:229:42)
    at Array.forEach (native)
    at SourceMapGenerator_applySourceMap [as applySourceMap] (/Volumes/WS/archive/.../webapp/node_modules/source-map/lib/source-map-generator.js:228:34)
    at applySourceMap (/Volumes/WS/archive/.../webapp/node_modules/vinyl-sourcemaps-apply/index.js:27:15)
    at Transform.<anonymous> (/Volumes/WS/archive/.../webapp/node_modules/gulp-cssnano/index.js:29:21)
    at process._tickCallback (internal/process/next_tick.js:103:7)

Not sure where the problem is, sass, css-nano, my gulp file?

kilianc commented 8 years ago

ref https://github.com/ben-eb/gulp-cssnano/issues/38

qlonik commented 8 years ago

Ooooh, I'm so glad I was able to find something that is relevant to my error!

I have absolutely the same problem. I have a set of .less files which I need to convert into css and add source map to those for development build and then those built files need to be minified and another source map attached to minified files. My gulp tasks are a little big, but essential part is the same as yours.

I have created simple project to test this. This project only includes index.less file which imports bootstrap installed as bower package and gulpfile.js which builds the style sheet.

// app/index.less
@import '../bower_components/bootstrap/less/bootstrap';
// gulpfile.js

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

gulp.task('css', function () {
  return gulp.src('app/index.less')
    .pipe($.sourcemaps.init())
    .pipe($.less()).on('error', errorHandler('less'))
    .pipe($.autoprefixer()).on('error', errorHandler('autoprefixer'))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('dev'));
});

gulp.task('css:min', ['css'], function () {
  return gulp.src('dev/index.css')
    .pipe($.sourcemaps.init({loadMaps: true}))
    .pipe($.cssnano()).on('error', errorHandler('cssnano'))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('dist'));
});

gulp.task('clean', function () {
  del(['dev', 'dist']);
});

const errorHandler = function (title) {
  return function (err) {
    gutil.log(gutil.colors.red('[' + title + ']'), err.toString());
    this.emit('end');
  };
};

Here one task is a dependency of another, in case they are not dependencies and run one after another, it seem that everything works correctly.

It looks like the issue is with relative path resolution in source maps. I'm saying this because if I move index.less to be beside bower_components and therefore import without going up up in folder hierarchy, everything works correctly. However, as soon as I import from a folder few levels higher, I get an error.

[15:16:03] [cssnano] Error in plugin 'gulp-cssnano'
Message:
    "/bower_components/bootstrap/less/normalize.less" is not in the SourceMap.

In the error message the path to one of the components of bootstrap does not have ../ anymore, although it should. It could also be an issue that I'm saving sourcemaps twice, but I dont think there should be any problem doing this - maps should just be overwritten on second save.

I can also break source maps generation doing another thing. With the css task being like this:

gulp.task('css', function () {
  return gulp.src('app/index.less')
    .pipe($.sourcemaps.init())
    .pipe($.less()).on('error', errorHandler('less'))
    .pipe($.sourcemaps.write())
    .pipe($.sourcemaps.init())
    .pipe($.autoprefixer()).on('error', errorHandler('autoprefixer'))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('dev'));
});

Here, I save sourcemap after running through less and initialize before autoprefixer. This time autoprefixer is throwing error:

[15:19:13] [autoprefixer] Error in plugin 'gulp-autoprefixer'
Message:
    "/bower_components/bootstrap/less/normalize.less" is not in the SourceMap.
Details:
    fileName: c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\app\index.css
Stack:
Error: "/bower_components/bootstrap/less/normalize.less" is not in the SourceMap.
    at SourceMapConsumer_sourceContentFor [as sourceContentFor] (c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\source-map\lib\source-map-consumer.js:703:15)
    at SourceMapGenerator.<anonymous> (c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\source-map\lib\source-map-generator.js:229:42)
    at Array.forEach (native)
    at SourceMapGenerator_applySourceMap [as applySourceMap] (c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\source-map\lib\source-map-generator.js:228:34)
    at _class.applyPrevMaps (c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\postcss\lib\map-generator.js:146:22)
    at _class.generateMap (c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\postcss\lib\map-generator.js:194:46)
    at _class.generate (c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\postcss\lib\map-generator.js:275:25)
    at LazyResult.stringify (c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\postcss\lib\lazy-result.js:226:24)
    at c:\Users\nvolodin\Code\tests\gulp-sourcemaps-test\node_modules\postcss\lib\lazy-result.js:163:27
    at process._tickCallback (internal/process/next_tick.js:103:7)

Which is essentially the same error.

So, it looks like the problem is not with less, sass, autoprefixer, css-nano. It is most likely the problem with gulp-sourcemaps or some other part inside gulp-sourcemaps.

qlonik commented 8 years ago

Side note:

If I modify my tasks this way:

gulp.task('css', function () {
  return gulp.src('app/index.less')
    .pipe($.sourcemaps.init())
    .pipe($.less()).on('error', errorHandler('less'))
    .pipe($.autoprefixer()).on('error', errorHandler('autoprefixer'))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('dev'));
});

gulp.task('css:min', ['css'], function () {
  return gulp.src('dev/index.css')
    .pipe($.sourcemaps.init())
    .pipe($.cssnano()).on('error', errorHandler('cssnano'))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('dist'));
});

Here, in 'css:min' task, when I init sourcemaps I removed the loading of previous sourcemaps. In this case it should not be loading previous sourcemaps and should not be looking on the content of previous ones. It should only create a map that links to the css file after less was run. However, I still get errors like this:

[15:31:16] [cssnano] Error in plugin 'gulp-cssnano'
Message:
    "/bower_components/bootstrap/less/normalize.less" is not in the SourceMap.

Which means that sourcemaps are still being read and something happens that it fails to find file (again, because of relative path issues)

kilianc commented 8 years ago

@qlonik re: your last comment, that's because your first sourcemaps.write() is missing the path '.'. The default behavior is to write sourcemaps inline in this case. If you ad the path back it will work as aspected.

qlonik commented 8 years ago

@kilianc Yep, for the dev build I would prefer to have inline sourcemap and for production to have it in separate file. I was just expecting that when I create sourcemaps for production css, it will not load inline css from previous step, but it does.

kilianc commented 8 years ago

Oh you're right, even if inline it should not load them...

kilianc commented 8 years ago

try sourcemaps.init({ loadMaps: false }) it may be a bug on sourcemaps module.

qlonik commented 8 years ago

The last suggestion didn't work. It does fail on the inline even though loadMaps is set to false.

You were right with the not inline idea. If I save development sourcemap in a separate file, then production one works correctly.

BTW, here is a project, for the reference. gulp-sourcemaps-test.zip

qlonik commented 8 years ago

Oh! This might be important. I also have the same thing with javascript files - I need to generate two sets of sourcemaps (inline for dev and in file for production). In case of js files, development is handled by webpack and sourcemap is generated by webpack, and production are handled by gulp-sourcemaps. In this case everything works correctly. Webpack is creating inline sourcemaps and gulp-sourcemaps pickups sourcemap (I'm using { loadMaps: true }) and for production files maps are correctly generated.

kilianc commented 8 years ago

same for me, js sourcemaps work correctly even on multiple passes (browserify -> uglify). I think somewhere down the pipeline stylesheet paths get altered by something

bent10 commented 8 years ago

maybe you should define sourceRoot .pipe(sourcemaps.write({sourceRoot: 'app'}))

gregbrown1229 commented 8 years ago

I had a similar problem today, and after much searching, came to find that the issue is with the current stable release of gulp-sourcemaps (1.6.0). In order to work around the issue, I had to use this:

.pipe(sourcemaps.write(undefined, { sourceRoot: null }))

Once I made that change, everything went smoothly.

Also, there's a fix in version 2.0.0-alpha of gulp-sourcemaps, if you're willing to update to an unstable version.

Hope this helps!

aude commented 8 years ago

I got this error, and found out that I ran autoprefixer() before sourcemaps.write().

for anyone that might stumble upon this error message for seemingly no reason, it could be an idea to take a second look at the order of your pipes.

sourcemaps should init() before any plugin and write() after any plugin, as shown.

codepuncher commented 7 years ago

Whilst the fix @gregbrown1229 posted did work for me, turns out the actual solution was what @aude said. Quite a simple thing, but easily missed. this:

.pipe(sm.init())
...
.pipe(sm.write())
.pipe(gulp.dest('assets/css/'))
.pipe(prefix({browsers: ['last 2 versions', '> 5%', 'Firefox ESR']}))
...

should have been this:

.pipe(sm.init())
...
.pipe(prefix({browsers: ['last 2 versions', '> 5%', 'Firefox ESR']}))
.pipe(sm.write())
.pipe(gulp.dest('assets/css/'))
...
vaske commented 7 years ago

@qlonik I have exactly the same issue but with sass. Did you manage to fix it?

qlonik commented 7 years ago

Hey @vaske. Nope.

I didn't find css sourcemaps to be the most important things to worry about and just disabled generation of source maps for css. Other people offered solutions though, have you tried those?

vaske commented 7 years ago

@qlonik basically I updated 'gulp-cssnano' to 2.0.0 version and it started working ok.