Jhaml, yet another javascript haml implementation

yushenwv 8年前發布 | 8K 次閱讀 HTML JavaScript開發 JavaScript

來自: https://github.com/soyuka/jhaml

JHAML

Note: Currently a work in progress, filters are not available yet

Lazy?Jump to usage

Introduction

jHaml stands for Javascript Haml. I'm using scoped packages:

npm install @soyuka/jhaml

Why another HAML implementation?

Because I wanted a streamable HAML implementation. Also, some things didn't work on javascript implementation as they should in comparison to the ruby version.

For example:

%div{attr1: 'one', 
  attr2: 'two'} some content

Or errors thrown for no obvious reasons:

%div test
  test

Also, I almost never need code interpretation inside HAML but I instead write html templates to be used by angular. This is why this parser provides two different streaming engines:

  • one that transforms haml to html
  • one that transforms haml to javascript which then evaluates to html

Both are implementing the same one-pass algorithm:

  • jhamltohtml has a really low memory footprint and is not executing javascript. It just transforms to HTML and writes data as it comes.
  • jhaml builds javascript in-memory, executes and then streams the result out.

What's different

It's a stream!

Also, when using code interpretation, the haml code is translated to strict ES6 javascript.

This means:

  • it requires node > 4
  • it runs with the help of es6 templates
  • you have to declare variables

For example withtj/haml.js implementation you was able to do:

- name = 'test'
%p= name

This implementation would require the variable to be defined, mainly because we're in strict mode:

- let name = 'test'
%p= name

You've only access (for now) to basic loops (while, for) and conditions (if, else, switch) but not .forEach or .map for bloc operations.

For example this will work:

- let a = [0,1,2].map(i => i+1)

  • for(let i in a) %p= a[i]</pre>

    You may think a forEach loop could work, for example:

    - ;[0,1,2].forEach(function(e)
    %p=e

    But this will not be closed properly. If you want to do things like that (you should not need this in a template), it'd be written like this:

    - ;[0,1,2].forEach(e => __html += `<p>${e}</p>`)

    __html is a global scope variable in which html is being appended.

    And here's how a switch would be implemented:

    - switch(interpolated)

    • case 'Test': %p Ok
    • break;
    • default: %p Not ok</pre>

      Basically, code that get's an indented block will be surrounded by { and } . Code that's on the same indentation will just be executed as is.

    An if/else condition is written like this:

    - if(disabled)
    %p Disabled

  • else if(disabled === false) %p Not disabled
  • else %p Disabled is not defined: "#{disabled}"</pre>

    You can of course execute you own methods:

    - let t = myfunction('foo')
    %p= t
    -# same result as:
    %p #{myfunction('foo')}

    Compatibility

    This script runs thetj/haml.js test suite except non-standard for each loops.

    This does not mean that it'll produce the same output!

    Usage

    npm install -g @soyuka/jhaml

    Programmaticaly, jhaml gives you two parameters :

    • the scope
    • options

    For example:

    const jhaml = require('jhaml')
    const fs = require('fs')
    const scope = {foo: 'bar'}

fs.createReadStream(source.haml) .pipe(jhaml(scope, {attributesseparator: ''}))</pre>

Current available options are:

  • attributes_separator (string): a separator for embed attributes. Default to - , {ng: {click: 'test()', if: 'available'}} will render ng-click="test()" ng-if: "available"
  • eval (boolean): Only available with the Javascript engine (ie when using code interpretation). If set to false, it'll output javascript instead of html.

With code interpretation

CLI

Format: jhaml [--eval] [json scope] [output file]

To javascript:

jhaml --no-eval < file.haml '{"foo": "bar"}'

To Haml, pipe output:

jhaml < file.haml '{"foo": "bar"}' > file.html

To Haml, creates a write stream:

jhaml < file.haml output.html

Programmatic

const jhaml = require('jhaml')
const fs = require('fs')
const scope = {foo: 'bar'}

fs.createReadStream(source.haml) .pipe(jhaml(scope))</pre>

Without code interpretation

CLI

jhamltohtml < file.haml > output.html
jhamltohtml < file.haml output.html

Programmatic

const jhaml = require('jhaml')
const fs = require('fs')
const scope = {foo: 'bar'}

fs.createReadStream(source.haml) .pipe(jhaml.tohtml(scope))</pre>

Gulp

See here for the full documentation

npm install @soyuka/gulp-jhaml --save-dev
gulp.task('haml', ['haml:clean'], function() {
  return gulp.src(['./client/haml/**/*.haml'])
    .pipe(haml({}, {eval: false}))
    .on('error', function(err) {
      console.error(err.stack) 
    })
    .pipe(gulp.dest('./html'))
})

Express

See here

Need another implementation? Please get in touch.

</article>

 本文由用戶 yushenwv 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!