straker/livingcss

pattern "../../css/main.css" does not match any file

Closed this issue · 31 comments

I'm getting this error when I'm trying to preprocess the context to link my output css file (I'm running gulp-livingcss against a Sass codebase).

My task:

const livingcssConfig = cssFilePath => {
    return {
        loadcss: false,
        preprocess: (context, template, Handlebars) => {
            return livingcss.utils.readFileGlobs(cssFilePath, (data, file) => {
                context.globalStylesheets.push(file);
            });
        }
    };
};

// development
gulp.task('livingcss:dev', () => {
    gulp.src(`${config.sass.path}/**/*.scss`)
        .pipe(livingcss(livingcssConfig(`../../${config.css.path}/${config.css.output}`)))
        .pipe(gulp.dest(`./${config.styleGuide.path}/${config.styleGuide.info}`));
});

When I go to the URL http://localhost:3000/style-guide/info/ I see the SG output but with the default styling. When looking at the output index.html, nothing was written between the user styles comment block. If I add that file path in manually, it now picks up my styles:

<!-- user styles -->
<link rel="stylesheet" href="../../css/main.css">
<!-- /user styles -->

What am I doing wrong?

As an aside, when I did that (manually added the css path), it picked up most of my styles but, for instance, my bare ole a tag styles did not, for whatever reason, actually get used (though things like body copy color, spacing, etc were). Not sure about that one either but I guess lets take it one step at a time :)

An pr was just merged in straker/gulp-livingcss#3 that might resolve this issue for you. The dest parameter was missing which correctly determines the relative path from the dest directory to linked stylesheets.

Thanks for merging my pull request and supporting the dest argument. I've got one final request.

The dest argument is now required in order to be able to pass an options object. Also there is no default value defined, so you won't be able to use the library like this: livingcss(null, {...}).

Wouldn't it be nice if the gulp library detects whether the first argument is an object (options) or a string (dest) and define default values if an argument is missing? If you like the suggestion, I would like to implement such functionality and submit another pull request.

This did not work. I did some digging in the livingcss code and arrived at these lines:

// read all source files and handlebar templates
utils.readFileGlobs(source, function(data, file) {
  parseComments(data, file, tags, context);

  // only load css files
  if (options.loadcss && path.extname(file) === '.css') {
    context.stylesheets.push(path.relative(dest, file));
  }
}),

My source files are .scss files and my output is a css file. That checks to see if the input files, not the dest path, is a css file and if it is it adds it to the stylesheets in the context. This will fail for anyone using Sass as the input. Hope this helps.

A quick follow up as I just realized this: I think the dest path should update globalStylesheets as I had in my livingcssConfig method above. I want to load the whole stylesheet that gets output from my sass compilation at the top of the page where the user styles should go. I think that's the part that's actually missing here, not sure though. I don't completely understand what the context.stylesheets is actually doing. :)

@derbaeuerle The dest parameter is more or less required. Since the loadcss options defaults to true, you'll need the dest parameter to get a correct relative path from the destination directory to the stylesheets. It also has a default value assigned to it by LivingCSS of the current directory, so you can pass null in.

I do like you're idea so that you don't have to use dest if you're not using loadcss (I do the same thing in the LivingCSS). So do create another pr and I'll merge it.

@reintroducing If you're using a preprocess, look at this issue

@straker Thanks, thats actually the issue I modeled my setup from, but I don't think it is doing what it's supposed to (also the URL to the issue you linked is not working). Let me explain my setup.

At the root of my project I have a /css directory and a /style-guide directory. The /css dir is where my Sass spits out my compiled file. /style-guide is where LivingCSS gets generated to (actually /style-guide/info/index.html). So if I supply a path of ./css/main.css to the preprocess method I get no errors and it puts the correct path provided in the user styles comment block of the generated index.html file for LivingCSS. The issue there though is that ./css/main.css is not the path where the CSS actually lives so now when I go to load that index.html file it doesn't exist and I see none of my styles in the style guide.

Hopefully you followed me along in all that but essentially what I would think I'd be able to do is define ../../css/main.css as the path for my global styles and that is actually what would get put in the comment block for user styles and my styles would show up in the generated HTML (which they do if I change that path manually in the output index.html file to what I need it to be). So, this error I'm getting is keeping me from being able to do that, I believe because it's looking for that file path from the root of my repo (where my gulpfile is and where I assume the plugin starts checking file paths from) at which point it sees that it doesn't actually exist and never puts it into my global stylesheets, rather it should be looking for it with relation to where the output index.html file is going to end up so that configurations like mine, that don't stem from everything being at the root (output, generated css, etc), will still work correctly.

Does that make sense?

I think I follow you. Your directory structure looks like this:

.
  css
    main.css
  style-guide
    info
      index.html

What I think you just need to do is do a path.relative from the dest to the location of css/main.css inside of your preprocess function

const livingcssConfig = cssFilePath => {
    return {
        loadcss: false,
        preprocess: (context, template, Handlebars) => {
            return livingcss.utils.readFileGlobs(cssFilePath, (data, file) => {
                context.globalStylesheets.push(path.relative(`./${config.styleGuide.path}/${config.styleGuide.info}`, file));
            });
        }
    };
};

Yep, thats exactly right. That being said, your suggestion produces pattern "./style-guide/info" does not match any file.

Hu, is there a public repo or something I could play with?

Unfortunately this is a private repo. Give me a few days and maybe I can put together a sample based on my setup and provide that instead. Is that ok?

Cool, thanks for doing that.

Ok, I got a few minutes here to put something together sooner than I thought.

https://www.dropbox.com/s/fl0mrgomvnlqaqc/livingcss-test.zip?dl=0

Just download, cd in, npm i, and then npm start (which will open the index file of the actual project, you can just ignore it). That will generate /style-guide and /css/main.css and you can then see nothing is being put in the user styles in /style-guide/info/index.html. You will see, in terminal (before webpack finishes), the error: pattern "./style-guide/info" does not match any file. The gulp tasks are located in /config/gulp/tasks/livingcss.js.

Do let me know if anything isn't clear or I've left something out. Thanks for taking the time to look at this, greatly appreciated.

Ok, I think I've got things figured out.

For reference, here is your code as saved in the link you gave me. I've annotated with comments the changes:

import path from 'path';
import gulp from 'gulp';
import livingcss from 'gulp-livingcss';
import config from '../../config.json';

const livingcssConfig = cssFilePath => {
    return {
        loadcss: false,
        preprocess: (context, template, Handlebars) => {
            return livingcss.utils.readFileGlobs(cssFilePath, (data, file) => {
                context.globalStylesheets.push(path.relative(cssFilePath, file));     // 3, 4
            });
        }
    };
};

// development
gulp.task('livingcss:dev', () => {
    gulp.src(`${config.sass.path}/**/*.scss`)
        .pipe(livingcss(
            `../../${config.css.path}/${config.css.output}`,                          // 2
            livingcssConfig(`./${config.styleGuide.path}/${config.styleGuide.info}`)  // 1
        ))
        .pipe(gulp.dest(`./${config.styleGuide.path}/${config.styleGuide.info}`));
});
  1. you pass the output directory of the style guide (/style-guide/info) as the cssFilePath parameter. You probably meant to pass the path to the css file (css/main.css). Since the gulpfile is running from the root of your app, you don't want to add the back dirs.
  2. passing the css file path here doesn't do anything for you in this instance since you turned off the loadcss option, so you can leave it as null if you're using the latest gulp-livingcss.
  3. since you need the relative path from the output directory of the style guide to the css file, you should use that as the relative path and not the cssFilePath parameter. So context.stylesheets.push(path.relative(./${config.styleGuide.path}/${config.styleGuide.info}, file));
  4. The globalStylesheets context property will add the stylesheet into the global space of the style guide. If you instead wanted the css file to be used to render your style guide patterns, you should use the stylesheets property instead. The reason for is that the style guide uses webcomponents to build each style guide pattern and so global stylesheets can't penetrate the patterns.

So in the end, you should end up with something like this which should get the file linked correctly:

import path from 'path';
import gulp from 'gulp';
import livingcss from 'gulp-livingcss';
import config from '../../config.json';

const livingcssConfig = (dest, cssFilePath) => {
    return {
        loadcss: false,
        preprocess: (context, template, Handlebars) => {
            return livingcss.utils.readFileGlobs(cssFilePath, (data, file) => {
                context.stylesheets.push(path.relative(dest, file));
            });
        }
    };
};

// development
gulp.task('livingcss:dev', () => {
    gulp.src(`${config.sass.path}/**/*.scss`)
        .pipe(livingcss(
            null,
            livingcssConfig(`./${config.styleGuide.path}/${config.styleGuide.info}`, `${config.css.path}/${config.css.output}`)
        ))
        .pipe(gulp.dest(`./${config.styleGuide.path}/${config.styleGuide.info}`));
});

@straker Thanks for taking a look at this. I set up the config as you specified and got rid of the errors. I see that some of my styles are working now, however, if you look at the headings, they've inherited their margins but not the actual font/colors they're supposed to be, for instance (Before doing this, you'll have to change the className portion in /sass/common/_typography.scss to be class for the @example block. This is a React project and I misunderstood the use of the code vs example blocks when I did this originally, apparently). It looks like the body styles get overridden by the global styles (which I think is why I was trying to originally put this in the globalStylesheets array).

Is the best way around this to create my own template and pass my final output CSS to that as well? Would that best be done in globalStylesheets or should I just directly link it in the template?

Again, really appreciate you looking at all this. I can tell, once I get this working correctly, it will be a fantastic tool :)

As an FYI I'm using react-styleguidist for the React components since I don't think this would properly handle all that but combined, these two tools will produce the style guide I'm looking for which will allow me to document my CSS and my React components. The reason this lives in the /info folder is because the React components will live in a /components folder at the same level and then I'll have an index.html file at the root of /style-guide bringing it all together. Just figured I'd explain why this is set up the way it is in case you were wondering.

@straker Hey, don't mean to be a bother but was just wondering if you had a chance to look at this?

Ya sorry, I've been looking into this and it's lead down a rabbit hole of problems. I've been spending the last few days trying different solutions which all failed, so I'm back at the drawing board.

As for your specific problem, due to web components, the html and body selectors in your CSS don't get applied to the contents of the web component. This is a similar problem that the SC5 Style Guide has, so as a workaround you can use their suggested workaround.

However, web components are giving me tons of problems since they are not natively supported in Safari or Firefox (even with the pollyfil). I'm thinking I'm going to stop using them, but that means I need to rethink how to encapsulate your styles so that the main pages's styles don't affect them.

I see. I'm actually thinking the other way. I ultimately will want my style guide to have the same styles (for the most part) as my component styles because my generated Sass spits out one file which is the source of truth for the styling for my whole project. Ultimately I'd want the SG to be in the same style as the project for consistency.

I created a style guide manually before for my day job (http://www.spothero.com/uniform, though some parts are broken and incomplete as we just transitioned to a new brand look and started to add React components, in general this whole system needs to be rethought and I'm hoping to use LivingCSS and React-styleguidist for this too when I get a chance to rewrite it, so don't judge :)) and there I use my site styles as well. For anything that needed custom styling that I wanted to display differently in the SG itself from what is on the site (maybe just things like headings or pre tags or whatever) I just added a namespace and styled that separately in the style guide Sass file.

This is why I'd also want the ability to provide a custom template to the SG (although I think I've seen where you can do that with LivingCSS, not sure, didn't dive that deep into it yet) where I'd just load my own CSS and JS, your output would still generate markup thats got your namespaces, and I'd then go in and style those from scratch (since your default CSS would be gone at this point, not in my template). I think ultimately everyone would want to do that, to brand the SG to their styling, so I would not spend as much time on worrying about that as it sounds like you are doing. What do you think of that approach? It would eliminate the need for web components as a bonus.

Yep, LivingCSS does support passing in you're own Handlebars template with the template option. Having a custom template was one of the contributing factors in creating this project (since a lot of style guide generators don't allow that).

That's great. So, I know you've probably been thinking about this the past few days, but just wanted to gauge where you're at in terms of how you're planning to proceed. I can stop working on my SG (which I'm doing right now anyway because I have a ton of other stuff to do) until you figure out how you're going to move forward with the rendering issues discussed here if you think you're going to head down a different road. I'd hate to put time into modifying it and then there is a complete rewrite, but at the same time I understand this is an open source project and not your day job so I want to be cognizant of that and not ask for the moon. Hopefully you understand where I'm coming from :)

If you create you're own template and just load the one CSS file to control the look, that part should be fine. That's exactly what https://familysearch.org/reference/styleguide/ does. Anything I change will just affect the default template and getting it working. As of right now, I don't have a good idea of when things will get implemented since everything I've looked into has hit a dead end.

Gotcha, thanks for everything in this issue. I'm going to go ahead and close it as the original issue has been resolved and at this point we're discussing the future of the project. Thanks again.

Just thought you'd like to know that I just put in a pr that will resolve both the body and html tag issue, as well as fix the problems I ran into with safari and firefox.

Thanks, I will take a look next chance I get.

Just thought you'd like to know that with v4.0.0, I've fixed the body and html tags and they should now apply their styles and cascade to the examples as expected.

Awesome, thanks! I have not had a chance to get back to working on the SG for my project but plan to come back to it soon.

Alright, I'm finally now getting back to this. I've changed nothing since we last spoke in my setup except I updated to v2.0.2 of gulp-livingcss. That now produces the following and I get no output:

Error: stream.push() after EOF
    at readableAddChunk (/Users/przybylski/Desktop/livingcss-test/node_modules/gulp-livingcss/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:179:15)
    at DestroyableTransform.Readable.push (/Users/przybylski/Desktop/livingcss-test/node_modules/gulp-livingcss/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:157:10)
    at DestroyableTransform.Transform.push (/Users/przybylski/Desktop/livingcss-test/node_modules/gulp-livingcss/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:123:32)
    at success (/Users/przybylski/Desktop/livingcss-test/node_modules/gulp-livingcss/index.js:73:17)

Any ideas?

Seems it a bug that's hard to squash... I'll see if I can track it down.

Alright, v2.0.3 should fix the problem.

Alright, so that fixed the issue, but I'm not seeing anything being put in user styles again. This is my task just as a refresher:

import path from 'path';
import gulp from 'gulp';
import livingcss from 'gulp-livingcss';
import config from '../../config.json';

const livingcssConfig = (dest, cssFilePath) => {
    return {
        loadcss: false,
        preprocess: (context, template, Handlebars) => {
            return livingcss.utils.readFileGlobs(cssFilePath, (data, file) => {
                context.stylesheets.push(path.relative(dest, file));
            });
        }
    };
};

// development
gulp.task('livingcss:dev', () => {
    gulp.src(`${config.sass.path}/**/*.scss`)
        .pipe(livingcss(null,
            livingcssConfig(
                `./${config.styleGuide.path}/${config.styleGuide.info}`,
                `${config.css.path}/${config.css.output}`
            )
        ))
        .pipe(gulp.dest(`./${config.styleGuide.path}/${config.styleGuide.info}`));
});

This outputs nothing in the user styles section of index.html and the CSS path resolves to ../../css/main.css which is correct from its location. What has changed and what do I need to update?

EDIT: I don't see my styles being applied to the examples even though I don't get any type of errors.

Ah, pushing to globalStylesheets instead works :) That was the thought process here, correct? If so, then this works great now.

Awesome, glad it works.