Giter VIP home page Giter VIP logo

bnsf's Introduction

bnsf - bem node single page application framework

Build Status Bower version

For FAQs and HOWTOs see wiki.

There is an yeoman generator for bnsf.

For usage example see bnsf-project-stub.

For more interesting usage example see try-bem-online.net, source code here.

Why bnsf?

  • Shared routing and templates between browser and server
  • Single page application easily
  • SEO-friendly
  • Connect middleware compatible
  • JavaScript all the way
  • BEM stuff
    • Methodology to rule the development process
    • Well-structured file system
    • CSS, JS, templates dependency management
    • Asynchronous JS module system (no global variables)
    • Semantic blocks for application building
    • Build process out of the box (including CSS and JS minification)
    • Unit tests easily (including tools for CSS/templates testing)

Shared routing and templates between browser and server

bnsf uses router-base internally. It's a router, inspired by Symfony 2 routing system, written in JavaScript, so it can work both on client and on server (node.js). If you want to add a page to your application, you will need to specify a route for the page in YAML format:

- id: main-page
  path: /

So, when user will open http://your-domain.com/, he will see the content of the main page. You need to create a template for the page into the folder of main-page block. bnsf uses BEMTREE and BEMHTML technologies for templates, so the simplest template looks like this:

block('main-page').content()('Hello world');

Router and templates work both on the client and on the server, so if user somewhere into your application will click on the link to main page, he will see the content of it without page reloading. In order to avoid copy-paste and hard code, router supports urls generation, both in templates:

path('main-page') // returns "/"

and in client or server JavaScript code:

router.generate('main-page'); // returns "/"

Single page application easily

Write your code once, use everywhere. Templates, routing and your JavaScript code are shared between the client side and server side, but it's smart sharing: you always can specify, which code should be only on client, which code should be only on server and which should run on both sides of your application. The same with routes. Applications, written on top of bnsf, are views only. You will need to write some part with http API separately, using any language: it can be another node.js server, PHP application or even Go server. Such architecture gives you all pros of separation View from Data. You can read more in awesome article from Nickolas Zackas here, but I want to specify a pair of advantages in the document:

  • Reuse of API server: one server for your web site, Android and iOS applications
  • Most changes of View are easy, because you don't need to change back-and logic

SEO-friendly

When user directly types the url of some page of your site and press Return, the whole page is generated on the server. So, when search bot opens pages, bnsf behaves the same way, even if the bot can't understand JavaScript. Links on your site are just usual links, without any anchors, so bots can parse it without any difficulties. All content is available, always.

Connect middleware compatible

bnsf uses connect www.senchalabs.org/connect/ under the hood, so you can use any of high-quality and well-tested connect middleware.

JavaScript all the way

bnsf written in JavaScript. Your code should be written in JavaScript or any other language, that can be compiled to JavaScript. Your templates and router configuration files becomes JavaScript. And it's cool, because bnsf application can run everywhere, where JavaScript can run.

BEM stuff

bnsf is a thin layer on top of bem-core, main BEM library, which provides JavaScript framework (i-bem), ym async modules system, BEMHTML declarative template engine and other cool base stuff.

bnsf's People

Contributors

apsavin avatar guria avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bnsf's Issues

Errors about block generations

I have following code:

block('user').content()(function () {
    return this.get('login', this.ctx.loginParams).then(function (data) {
        if (data.body.authenticated) {
            return [
                data.body.user.name,
                {
                    block: 'link',
                    content: 'logout',
                    url: path('page-logout')
                }
            ];
        }

        return {
            block: 'link',
            content: 'Authenticate through GitHub',
            url: path('github-auth')
        };
    });
});

Route for page-logout is not set, it causes the block is not rendered at all without any errors in console.

I wanna see warning or error in the console

Improve logging

Need to log messages on several levels, such as error, warning, info, debug etc. It's very important to log requests and responses on most verbose level.

Also want to mention specific situation: if API returns not JSON with application/json header then all you see in console is just a mention about URL and the fact JSON has not parsed. I think in this situation not only original error should be logged but also whore response.body

Non-informative stack trace

When something goes wrong I get stake trace like this:

14:22:02.568 - error: Error process page /test-menu GET Error: Parameter "filePath" has bad value "undefined", not suitable for path generation
    at RouterBase._getParameterValue (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/node_modules/router-base/lib/router-base.js:435:19)
    at /home/jifeon/projects/bnsf-adwiki/libs/bnsf/node_modules/router-base/lib/router-base.js:374:30
    at String.replace (native)
    at RouterBase._generate (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/node_modules/router-base/lib/router-base.js:370:30)
    at RouterBase.generate (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/node_modules/router-base/lib/router-base.js:348:29)
    at BEMContext.<anonymous> (/home/jifeon/projects/bnsf-adwiki/desktop.bundles/index/index.bemtree.js:807:35)
    at run (/home/jifeon/projects/bnsf-adwiki/desktop.bundles/index/index.bemtree.js:179:15)
    at BEMContext.<anonymous> (/home/jifeon/projects/bnsf-adwiki/desktop.bundles/index/index.bemtree.js:120:14)
    at bodyHandler (/home/jifeon/projects/bnsf-adwiki/desktop.bundles/index/index.bemtree.js:98:54)
    at apply (/home/jifeon/projects/bnsf-adwiki/desktop.bundles/index/index.bemtree.js:119:40)

Error message is pretty useful and complete, but stack trace is uninformative. I'm talking about:

/index.bemtree.js:807:35

It's really annoying moment during usual development

Add tests for POST requests

  1. for one request
  2. for several requests in one
  3. for formData request
  4. for error responses: status 400, status 500

Default API routing options

How can I specify defaults for API routing. Here is it:

- id: auth
  path: /auth
  host: localhost:1337
- id: repos
  path: /user/repos
  host: localhost:1337

I do not want to copy the host field.

Authorization redirect

Suppose I do request to the api and get 403 status. So I want to redirect user to login page. How can I do it?

Redirect for unauthorized user

Suppose I have a number of pages which can be accessed only by authorized users. Of course I can check authentication inside each page and redirect user to login page if he is unauthorized. But I do not want to copy any piece of code. By the way how can I do redirect?
I think the special place must exist where I can define the rules for the privacy policy (maybe it is routing?)

Sometimes BEM context is undefined during page generation

How to reproduce:

Suppose I have a page and a block inside it. Here is bemhtml for the block:

block('entity')(
    elem('label')(
        tag()('span')
    ),

    elem('short-description')(
        tag()('span'),

        match(this.ctx.shortInfo)(
            content()(function () {
                return ' - ' + this.ctx.shortInfo;
            })
        )
    )
);

It fails with error

Error process page /backbonex/backbone.view.elements GET TypeError: Cannot read property 'shortInfo' of undefined
    at BEMContext.templates (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:1103:23)
    at run (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:165:13)
    at BEMContext.<anonymous> (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:114:14)
    at bodyHandler (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:92:54)
    at apply (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:113:40)
    at bemApply (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:363:20)
    at BEMContext.ctx (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:704:13)
    at run (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:173:15)
    at BEMContext.<anonymous> (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:114:14)
    at bodyHandler (/home/jifeon/projects/adwiki__front/bundles/index/index.bemhtml.js:92:54)

Of course there is a workaround: just match this.ctx && this.ctx.shortInfo, but there is nothing about it in the bem docs, and I think it's because ctx must be defined every time.

Error appears during page block generation.

variables for development environment

Now bnsf looks at BEMHTML_ENV=development, BEMTREE_ENV = development env variables to recognize development environment, but there is NODE_ENV variable which used by many other libraries. Maybe we should look at this if BEMHTML_ENV and BEMTREE_ENV are not set?

Listen to form.submit as well as link clicks

Now bnsf automatically routes user to URL specified in the href attribute of the links using AJAX, so we get SPA very easy. I think it could behave itself for forms in similar way

Uncought error in API requester

SyntaxError: Unexpected token �
    at Object.parse (native)
    at ApiRequester.decl._processBody (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/blocks/api-requester/api-requester.node.js:102:29)
    at Request._callback (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/blocks/api-requester/api-requester.node.js:55:33)
    at Request.self.callback (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/node_modules/request/request.js:121:22)
    at Request.emit (events.js:98:17)
    at Request.<anonymous> (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/node_modules/request/request.js:985:14)
    at Request.emit (events.js:117:20)
    at IncomingMessage.<anonymous> (/home/jifeon/projects/bnsf-adwiki/libs/bnsf/node_modules/request/request.js:936:12)
    at IncomingMessage.emit (events.js:117:20)
    at _stream_readable.js:929:16

This error occurs if response from the api is not in JSON format

Possibility to render page always on the client

I have page with error inside bemtree. It's very convenient to debug it when it renders on client. Debug it during generation on server is pretty hard so I suggest the following:

  • add an option to generate a page on the client even for first load
  • add info to wiki about how to debug it on the server

Why links can't be used inside BEMHTML

It's very often situation, when links have no relation to data transformation, they are just for decoration, their place is inside BEMHTML, but we can't use them there because path is not reachable inside BEMHTML. Why?

Problem with static server

  1. run gulp
  2. include some styl file into the build process
  3. create a mistake in the file
  4. try to continue the work :)

Current result: static server falls down and stops watching the files, if you break gulp work and run it again it won't help you, because static server process is detached. You need to stop the node process manually

Expected:

  1. static server continues working if an error happens.
  2. static server stops at the same time the gulp does.

How can I render response to a custom block

Suppose I have a page with list of links, each link refers to concrete data which should be loaded by AJAX. I want to use bundled mechanism for blocks loading aka request-listener but do not want replace the whole page but specific block. How can I do it? You can give me a short answer and I will write an article to the wiki.

Infinite loader

API is not run. I tried to open the page and see 502 in console:

Start process page page-500
Error process page / GET { error: '<html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body bgcolor="white">\r\n<center><h1>502 Bad Gateway</h1></center>\r\n<hr><center>nginx/1.8.0</center>\r\n</body>\r\n</html>\r\n',
  body: '<html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body bgcolor="white">\r\n<center><h1>502 Bad Gateway</h1></center>\r\n<hr><center>nginx/1.8.0</center>\r\n</body>\r\n</html>\r\n',
  response: { statusCode: 502, statusText: undefined },
  handled: true }
API request GET http://api.adwiki.dev/auth/github/callback has status 502
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.8.0</center>
</body>
</html>

but browser wait for something... and wait and wait...

How can I get cookie for API server

Cookies for API server are stored inside bnsf, but I want to connect to API server directly by websockets and of course I lose my authorization because I don't have necessary cookies on the client. I remember that I have possibility to write my own controllers in bnsf (I think I can get my cookies this way) but there is no any docs about it.

I think:

  1. we should pay more attention to this issue and make cookies proxying more configurable
  2. need to write some docs about using controllers

Mixed content in desktop.bundles

Initially there are only four files in the desktop.bundles directory, but after bem make files that generated automatically are placed to the same directory. It is very inconvenient. I want it be in separated places.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.