rotundasoftware / parcelify

Add css to your npm modules consumed with browserify.
MIT License
251 stars 20 forks source link

Concatenate all found sass files and then compile #14

Closed johanneslumpe closed 9 years ago

johanneslumpe commented 9 years ago

Given the following situation:

Is is possible to achieve this with parcelify? Right now it looks like that it compiles each set of files on its own, which makes defined variables from other modules inaccessible.

From the top of my head I'd assume that for something like this a temporary scss file, which imports all scss files from the project's root directory with their full path (node_modules/module/some/file.scss) so that sass can correctly process their imports, has to be created. This file would then be compile-able and all variables would be available. Is there anything like this built into parcelify or is this use case way too specific?

dgbeck commented 9 years ago

hi @johanneslumpe ! Let me make sure I understand.. ideally you would like to import a scss file in the parent module, say settings.scss, from the plugin modules, by doing this in the plugin's scss:

@import "parent-module/settings.scss";

(Where parent-module is a dependency of the plugin module.)

Or, said another way, you are looking for a way to use the node require resolution algorithm with scss imports.

Is this correct?

johanneslumpe commented 9 years ago

@dgbeck Yeah you could say it like that. But since it might be cumbersome to directly require the settings.scss file in the scss for each plugin, I thought it might be nice to have it globally available for each plugin. That's why I thought about concatenating the files first. But of course specifying the file manually would work too.

dgbeck commented 9 years ago

Hi @johanneslumpe . Great. Very cool idea.

I think the cleanest approach to address this issue would be to write a small transform that could be applied to scss files. The transform would scan the files for scss @import directives and then replace relative paths with absolute paths using the node resolve algorithm.

A very similar transform is done by cartero to translate ##asset_url() directives from relative paths to urls. Building off of that code, your transform might look something like this (untested):

var through = require('through');
var resolve = require( "resolve" );
var path = require( "path" );
var pathMapper = require( "path-mapper" );

module.exports = function( file, options ) {
    var data = '';

    if( path.extname( file ) !== ".scss" )
        return through();
    else
        return through(write, end);

    function write( buf ) {
        var _this = this;
        var res = buf.toString( 'utf8' );

        res = res.replace( /@import\(\ *(['"])([^']*)\1\ *\)/, function( wholeMatch, quote, originalPath ) {
            try {
                resolvedPath = resolve.sync( originalPath, { basedir : path.dirname( file ) } );
            } catch ( err ) {
                return _this.emit( 'error', new Error( 'Could not resolve @import( "' + originalPath + '" ) in file "' + file + '": ' + err ) );
            }

            return resolvedPath;
        } );

        this.queue( new Buffer( res, 'utf8' ) );
    }

    function end() {
        this.queue( null );
    }
};

You can then publish this little transform as a npm module and include in your module's package json, for example:

{
  "name": "my-module",
  "description": "Example module.",
  "version": "1.5.0",
  "style" : "*.scss",
  "transforms" : [ "sass-import-resolver", "sass-css-stream" ],
  "dependencies" : {
    "sass-import-resolver":"~0.0.1",
    "sass-css-stream": "~0.0.1"
  }
}

Keep us posted if you write such a transform. Seems like a very useful one! Thanks for sharing this use case!

dgbeck commented 9 years ago

Additional thought.. I could see there being other use cases for this transform, besides just in scss imports. If you were to make it even more module it could be applied to those other cases. For instance, you could make the transform scan all files for strings of the form:

##node_resolve_path( './relative/path' );

and change the relative path to an absolute path. Then in your scss files, you could do:

@import( "##node_resolve_path( 'parent-module/settings.scss' )" );

Also that way you have more control over which paths are transformed and which are left alone.

johanneslumpe commented 9 years ago

@dgbeck thanks for the input :) I will definitely post back after getting that transform to work! Thanks for the starting point.

dgbeck commented 9 years ago

Going to close this for now to keep a clean shop. @johanneslumpe if you make any progress on this front pls post back here. Thx!

johanneslumpe commented 9 years ago

@dgbeck I have had it working for some time, it just has no tests, that's why I didn't upload it anywhere. I might just upload it to github anyway soon.

majgis commented 9 years ago

@johanneslumpe I would like to see what you came up with, if you are willing to publish to github and a gist is fine too. I am dealing with this same problem at the moment. The method I had envisioned was to use npm link to share a common resource across packages, keeping the isolation of the package intact, but I have yet to inspect the output from parcelify and I would like to compare against your solution. Thanks!

johanneslumpe commented 9 years ago

@dgbeck @majgis I just published a version, albeit without tests: https://www.npmjs.com/package/parcelify-import-resolver

dgbeck commented 9 years ago

Cool! Thanks for sharing!