fbrctr / fabricator

A tool for building website UI toolkits and style guides
http://fbrctr.github.io/
MIT License
1.11k stars 124 forks source link

Question: Any ideas how to include js in materials? #240

Closed goesbysteve closed 8 years ago

goesbysteve commented 8 years ago

I'd like to have the javascript that enhances a material to be in the material itself. Mainly this is for documentation so opening the code view shows the markup and the javascript. We will be using Webpack in our production build and I can handle the chunks etc but in production a chunk will be included in a particular page template which requires/imports the dependent material's js, so we don't have a single point of entry there. In the component library I would like developers to be able to see the markup and the javascript in context.

e.g.

<button class="button">Submit</button>

<script>
    var myModule = require('./modules/my-module');
    myModule.init({config: {}});
</script>

Best I could come up with was commenting out the script in a html material.

e.g.


---
notes: |
  These are notes associated with this `button` component.

---
<button class="button">Submit</button>

<script>
//var myModule = require('./modules/my-module');

//myModule();
</script>

Ideally I'd like js to run in context to require the material's script but I'm OK the javascript being encoded so it doesn't run, it's just content. I couldn't find a way to do that. I tried the markdown helper, using a .md file rather than html but they added code & pre in a way that caused errors in the markup and the content didn't get handled as the code view usually does, which I understand.

I saw in the demo that there was a Docs>Javascript section but I didn't really want to separate the material from it's javascript. Maybe I'm unknowingly fighting against an intentional design principal of Fabricator here so I'm totally willing to be enlightened too.

Hope this explains my thinking OK.

Thanks very much,

Steve

LukeAskew commented 8 years ago

Couple of options here.

First, the fact that JS doesn't run in context of the material is a bit of an intentional design decision on my part. I believe its best practice for toolkits to run automatically, with no requirement on the end developer to execute javascript. This enhances the portability of your toolkit - drop a material on the page and it just works. There are certain code design decisions you'll have to make in order to achieve this, but that part is up to you and your stack.

However, in many cases you'll need to document javascript APIs for your materials. I like using the notes front-matter for this. Here's an example from a toolkit I recently built:

fabricator source

goesbysteve commented 8 years ago

Yup I can see that approach. It may or may not work for us as the UI system is part of a white label site with a lot of code which we may choose to have in separate webpack bundles but I'm ok with the toolkit in Fabricator and production being bundled/split differently as long as the source modules are the same. That's a build issue. I may of course come back to that thought!

The way you wrote dropdown looks good and better than I had. My only thought would be having the JS in the code view rather than notes view. Maybe that's just a matter of getting used to it. It does help keep in in context with a fuller description of use. So I like it and I think I'll try that.

Thanks Luke I really appreciate your reply.

DTwigs commented 8 years ago

Where do you initialize the dropdowns to show a working dropdown in your fabricator project? I don't like the idea of including that JS in your toolkit.js because it should be up to the consumer when to initialize the dropdowns.

I do really like this notes approach though for documentation purposes.

LukeAskew commented 8 years ago

@DTwigs this is a bit of an architecture challenge I've experienced with toolkits. In the past my approach has been to do some DOM node checking on page load, then initialize anything that's present. If you're using jQuery, this is handled within the upfront node selection e.g. $('.some-component'). So you end up with something like:

$('.dropdown').each(function () {
  var dropdown = new Dropdown($(this));
});

The drawback to this approach is that you have to create additional initialization and destroy methods for when components are dynamically added to the DOM. I've tried a few things in the past. Hoping to publish some real world patterns during my next project.