rollup-plugin-sass icon indicating copy to clipboard operation
rollup-plugin-sass copied to clipboard

Watch partials

Open erezmus opened this issue 8 years ago • 26 comments

Hi,

I'm currently using the plugin to generate my css from an scss file imported in the main js file as such:

import './../styles/main.scss'

Running the rollup command with the watch flag, when i save the main.scss files it recompiles fine, however if I change any of the partials, its not detected.

Is there a way for the rollup watch to extend to those partials?

erezmus avatar Feb 16 '17 15:02 erezmus

Hi @mwerezi , I think --watch flag only helps recompile automatically. so u have to refresh browser manually. Maybe u need live reload during development.Checkout quick start docs from rollup wiki.

I use below configuration file and auto recompile works:

// package.json
{
  "devDependencies": {
    "rollup": "^0.41.4",
    "rollup-plugin-babel": "^2.7.1",
    "rollup-plugin-sass": "^0.4.9",
    "rollup-watch": "^3.2.2"
  }
}
// rollup.config.js
import babel from 'rollup-plugin-babel'
import sass from 'rollup-plugin-sass'

export default {
    entry: './src/index.js',
    dest: './dist/index.js',
    format: 'cjs',
    plugins: [
        sass({
            insert: true
        }),
        babel({
            runtimeHelpers: true
        })
    ]
}
> ./node_modules/.bin/rollup -c --watch
bundling...
bundled in 318ms. Watching for changes...
bundling...
bundled in 59ms. Watching for changes...
bundling...
bundled in 33ms. Watching for changes...

differui avatar Feb 17 '17 08:02 differui

I think what @mwerezi is saying is that rollup is not aware of the sass dependency tree and does not recompile sass dependencies but only the entry file (i.e. main.scss).

Let's say my main.scss imports (with sass imports) a file some/partial.scss:

@import 'some/partial.scss';

If I modify main.scss it will be detected by rollup as it's in the dependency tree via an es6 import. But if I modify some/partial.scss, it won't as rollup has no idea of the sass dependency tree.

@mwerezi One workaround is to import everything with es6 imports and not use sass @import at all.

@differui Still it feels we are losing something here. I don't really know what facilities rollup offers to plugin authors, but do you think there would be a way to make rollup aware of those sass @imports?

ngryman avatar Mar 09 '17 08:03 ngryman

@mwerezi Oops, sorry for misunderstood.

We use node-sass compile .scss and .sass in this plugin.So it's not possible that rollup can track dependency tree of stylesheets for us.

rollup-watch looks like using modules entry to track dependencies.As we can see this plugin leave this entry empty.

// ./src/index.scss
@import './partial.scss';

body {
    font-size: 12px;
    color: green;
}
// ./src/index.js
import css from './index.scss';

console.log(css);
// build.js
const rollup = require('rollup');
const sass = require('rollup-plugin-sass');
const babel = require('rollup-plugin-babel');

rollup.rollup({
    entry: './src/index.js',
    dest: './dist/index.js',
    format: 'cjs',
    plugins: [
        sass({
            insert: true
        }),
        babel({
            runtimeHelpers: true
        })
    ]
}).then(bundle => {
    console.log(bundle.modules);
}).catch(e => {
    console.log(e);
});

And here is the output:

[
  {
    id: ~/src/index.scss',

    // rollup-watch track nothing
    dependencies: [], 
    code: 'export default ___$insertStyle("body {\\n  font-size: 12px; }\\n\\nbody {\\n  color: green; }\\n");;',
    originalCode: '@import \'./partial.scss\';\n\nbody {\n    color: green;\n}\n',
    ast:
     { type: 'Program',
       start: 0,
       end: 95,
       body: [Object],
       sourceType: 'module' },
    sourceMapChain: [ [Object], [Object] ],
    resolvedIds: {}
  },
  {
    id: '~/src/index.js',

    // rollup-watch track index.scss
    dependencies: [ '/Users/differui/Sandbox/rollup-watch/src/index.scss' ],
    code: 'import css from \'./index.scss\';\n\nconsole.log(css);',
    originalCode: 'import css from \'./index.scss\';\n\nconsole.log(css);\n',
    ast:
     { type: 'Program',
       start: 0,
       end: 50,
       body: [Object],
       sourceType: 'module' },
    sourceMapChain: [ [Object] ],
    resolvedIds: { './index.scss': '~/src/index.scss' } 
  }
]

I don't know how other plugins put those stuff in modules (maybe include resolvedIds) for now. But take a step forward on workaround that @mwerezi talked.This plugin takes over the dirty work that transpile @import ./path/to/style.scss to import ./path/to/style.scss as part of the output.As so the tracking maybe works.

differui avatar Mar 09 '17 16:03 differui

@differui I think it's potentially possible to inject sass dependencies into rollup as others plugins do it in some way. commonjs would be the most famous. It parses the ast and search for require and then somehow (transpilation?) make rollup aware of it.

So theoretically I guess, it would be possible to transpile or grab every @import in the sass source and make rollup aware of those dependencies. How to do that, I don't know 🤓

ngryman avatar Mar 09 '17 17:03 ngryman

@Rich-Harris sempai, do you think it would be something achievable?

Context

ngryman avatar Mar 09 '17 17:03 ngryman

This is something that we'd like to implement: https://github.com/rollup/rollup/issues/1203

Does the proposal in that issue (returning a { code, map, dependencies } object, or a promise that resolves to one) seem like it would work? I'm not familiar with how the SASS compiler works, but presumably it has a way of reporting which files were imported?

Rich-Harris avatar Mar 09 '17 19:03 Rich-Harris

@Rich-Harris Thanks for your quick feedback 🎉 Given my limited knowledge of rollup plugin API I feel that https://github.com/rollup/rollup/issues/1203 would allow to resolve this issue.

@differui What do you think?

ngryman avatar Mar 09 '17 20:03 ngryman

@Rich-Harris It's fine to have the mechanism that plugin tells rollup dependencies information. @mwerezi I did little doc research.node-sass flatten dependency tree into a plain array which stored as includedFiles in result-object.

// sample.scss
@import "partical-a.scss";
@import "partical-b.scss";

body {
    color: red;
}
// partical-a.scss
@import "./partical-c.scss";

body {
    font-size: 12;
}
// partical-b.scss
body {
    font-style: italic;
}
// partical-c.scss
body {
    background-color: white;
}
// compile.js
const fs = require('fs');
const sass = require('node-sass');

sass.render({
    data: fs.readFileSync('./sample.scss').toString()
}, (err, result) => {
    if (err) console.error(err);
    else console.log(result.stats.includedFiles);
});

Here is the output:

[ 
  '/absolut/path/to/partical-a.scss',
  '/absolut/path/to/partical-b.scss',
  '/absolut/path/to/partical-c.scss'
]

differui avatar Mar 10 '17 01:03 differui

@ngryman If I remember well, I tried that but then I had a problem with rollup-plugin-hash although i've now switched to doing my own hashing. I might give es6import a go again

erezmus avatar Mar 16 '17 14:03 erezmus

@ngryman You've propose workaround:

One workaround is to import everything with es6 imports and not use sass @import at all. I've tried it but sass is loosing context when files are setup in js file.

For example if I have Styles.js with: import 'scss/variables.scss; import 'scss/components.scss

Variables defined in variables.scss are not visible in components.scss. Do you have idea how to workaround this?

pawel-kontakt avatar Apr 18 '17 09:04 pawel-kontakt

@pawel-kontakt I think scss/variables.scss should be imported both Styles.js and scss/components.scss. One for deps tracking in rollupjs and another for keeping context in sass.

differui avatar Apr 18 '17 14:04 differui

@pawel-kontakt You have to use sass @import for sass related stuff (variables, mixins, ...). You only use JavaScript import for outputed CSS.

scss/components.scss

@import 'variables';

// ...

index.js

import './scss/components.scss';

@differui No need to import scss/variables.scss in JavaScript realm as it does not output anything.

ngryman avatar Apr 20 '17 08:04 ngryman

@ngryman If scss/variables.scss not imported in JavaScript realm, rollup.js can not trace it and not rebuild after scss/variables.scss changed.Cause we lack the mechanism that plugin tells rollup.js dependencies information.

differui avatar Apr 21 '17 02:04 differui

I was afraid that including same file in js and scsss will cause it content to be duplicated in output - but it is not - I've tested it in simple config.

For me this solution is good enough, thank you.

pawel-kontakt avatar Apr 21 '17 05:04 pawel-kontakt

@pawel-kontakt It's OK.rollup.js will eliminate unused variables.

differui avatar Apr 21 '17 07:04 differui

@differui Yes true forgot about that.

ngryman avatar Apr 21 '17 07:04 ngryman

I solved it for the less plugin by declaring the less imports as ES module dependencies (as @differui suggested). Now rollup considers these files as dependencies and watches them too.

katrotz avatar Apr 25 '17 12:04 katrotz

I solved @pawel-kontakt's issue in a new Sass plugin: http://github.com/nathancahill/rollup-plugin-collect-sass

It does a first pass to collect all of the imports, then compiles all of the imported Sass in a single context, so variables are available across JS imports, without risking CSS duplication (Rollup handles JS duplication but not CSS).

nathancahill avatar May 09 '17 19:05 nathancahill

Is there any solution to this issue? Looks like the MR #30 would fix it, but it needs an update

hultberg avatar Jul 29 '18 13:07 hultberg

https://github.com/es128/progeny could be integrated to recursively find all dependencies

sormy avatar Oct 26 '18 00:10 sormy

Any updates on the issue?

kazzkiq avatar Oct 04 '19 20:10 kazzkiq

I have a similar problem with rollup-plugin-scss. I was considering switching to this project, but defining SCSS partials in an .js file is not an acceptable solution to me. Will look into this more.

Wolfr avatar Feb 24 '20 13:02 Wolfr

@kazzkiq, rollup-plugin-postcss support partials

sidati avatar Jun 10 '20 01:06 sidati

As @sidati said, the PostCSS plugin works with partials. And PostCSS supports SASS as a plugin.

So perhaps using PostCSS may be a fit substitute for this project:

  1. Remove this plugin from your project;
  2. Add rollup-plugin-postcss instead;
  3. Add SASS plugin in your rollup.config.js;

kazzkiq avatar Jun 10 '20 01:06 kazzkiq

I don’t get it. Isn’t partials the most important thing about sass? What is a sass plugin without partials?

moritzebeling avatar Nov 23 '20 09:11 moritzebeling

This is what works for me if that helps

const mySass = (options) => ({
	name: 'my-sass',
	async load(id) {
		if (!id.endsWith('.sass')) {
			return
		}

		const sassResult = sass.renderSync({ file: id, indentedSyntax: true })
		sassResult.stats.includedFiles.forEach(it => this.addWatchFile(it))
		
		const referenceId = this.emitFile({
			type: 'asset',
			name: path.basename(id, '.sass') + '.css',
			source: sassResult.css,
		})

		return `export default import.meta.ROLLUP_FILE_URL_${referenceId}`;
	},
})

JanTvrdik avatar Nov 23 '20 11:11 JanTvrdik

Tests written (#129 ) - This is currently fixed in library versions 1.12.22+.

elycruz avatar Apr 17 '24 15:04 elycruz