├── .eslintignore ├── test ├── views │ └── index.tag ├── layout.test.js ├── index.test.js ├── simulate_prod.test.js └── basic_example.test.js ├── example ├── basic │ ├── views │ │ ├── hello.tag │ │ ├── footer.tag │ │ └── index.tag │ ├── layout │ │ └── layout.html │ └── server.js ├── WiP_todo │ ├── views │ │ ├── fn.js │ │ ├── footer.tag │ │ └── index.tag │ ├── layout │ │ └── layout.html │ └── server.js └── counter │ ├── layout │ └── not_default.html │ ├── views │ └── index.tag │ └── server.js ├── CONTRIBUTING.md ├── .travis.yml ├── .istanbul.yml ├── .gitignore ├── package.json ├── lib └── index.js └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | bundle.js 3 | -------------------------------------------------------------------------------- /test/views/index.tag: -------------------------------------------------------------------------------- 1 | 2 |

Hello { opts.title }

3 |
4 | -------------------------------------------------------------------------------- /example/basic/views/hello.tag: -------------------------------------------------------------------------------- 1 | 2 |

Hello {opts.name}!

3 |
4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Please view our [contribution guidelines](https://github.com/dwyl/contributing) 2 | -------------------------------------------------------------------------------- /example/basic/views/footer.tag: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /example/WiP_todo/views/fn.js: -------------------------------------------------------------------------------- 1 | console.log('the fn.js file/code gets included in the "compiled" JS file with all the tags!'); //eslint-disable-line 2 | -------------------------------------------------------------------------------- /example/counter/layout/not_default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Different Layout 4 | 5 | 6 | <<>> 7 | 8 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "6" 5 | before_install: 6 | - pip install --user codecov 7 | after_success: 8 | - codecov --file coverage/lcov.info --disable search 9 | -------------------------------------------------------------------------------- /example/basic/views/index.tag: -------------------------------------------------------------------------------- 1 | 2 |

Hello World { time } ... { title }

3 |
4 | 8 |
9 | -------------------------------------------------------------------------------- /.istanbul.yml: -------------------------------------------------------------------------------- 1 | verbose: false 2 | instrumentation: 3 | root: ./lib 4 | excludes: [] 5 | include-all-sources: true 6 | check: 7 | global: 8 | branches : 100 9 | functions : 100 10 | lines : 100 11 | statements : 100 12 | -------------------------------------------------------------------------------- /example/counter/views/index.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /example/basic/layout/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Basic Example 7 | 8 | 9 | 10 | <<>> 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/layout.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | 5 | var server = require('../example/counter/server.js'); 6 | 7 | test('render with different layout', function (t) { 8 | var options = { url: '/' }; 9 | 10 | server.inject(options, function (response) { 11 | var expected = 'Different Layout'; 12 | 13 | t.ok( 14 | response.result.indexOf(expected) > -1, 15 | 'Different layout html given and correctly produced' 16 | ); 17 | server.stop(t.end); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /example/WiP_todo/layout/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Todo Example 7 | 8 | 9 | 10 | 11 | <<>> 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/WiP_todo/views/footer.tag: -------------------------------------------------------------------------------- 1 |
2 | {remaining} item left 3 | 8 | 9 | 15 |
16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .DS_Store 40 | db 41 | 42 | #goodparts symlink 43 | .eslintrc.js 44 | 45 | bundle.js 46 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | var HapiRiot = require('../lib/index.js'); // yes, the /index.js can be omitted 8 | 9 | test('Renderer has compile method', function (t) { 10 | t.equal(typeof HapiRiot, 'object', 'HapiRiot is an Object'); 11 | t.equal(typeof HapiRiot.compile, 'function', 'HapiRiot has a compile method'); 12 | t.end(); 13 | }); 14 | 15 | test('Manually test the compile method (witout a server)', function (t) { 16 | var filename = path.join(__dirname, 'views', 'index.tag'); 17 | // yes, the format of the .compile method is a curry... 18 | var actual = HapiRiot.compile( 19 | fs.readFileSync(filename, 'utf8'), 20 | { 21 | filename: filename, 22 | compiledFileRoute: '/test.js' 23 | } 24 | )({ title: 'Beautiful!' }); 25 | var include1 = '

Hello Beautiful!

'; 26 | var include2 = 'riot.mount("index",{"title":"Beautiful!"})'; 27 | var include3 = ' 60 | 61 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Path = require('path'); 4 | var Riot = require('riot'); 5 | var fs = require('fs'); 6 | 7 | var DEFAULTS = { removeCache: process.env.NODE_ENV !== 'production' }; 8 | 9 | var layoutCache = {}; 10 | var tagsLoaded = null; // when null all tags in view directory will be loaded 11 | 12 | /* 13 | * Riot does not Automatically resolve and require nested tags. 14 | * so loadTags requires all files in the template's directory 15 | * QUESTION: do we need to require recursively? discuss: https://git.io/viqjY 16 | */ 17 | function loadTags (filename) { 18 | var viewdir; 19 | 20 | if (tagsLoaded) { 21 | return; // early return since have already made the requires 22 | } 23 | 24 | viewdir = filename.slice(0, filename.lastIndexOf('/')); 25 | tagsLoaded = fs.readdirSync(viewdir).map(function (file) { 26 | var filepath = Path.join(viewdir, file); 27 | 28 | if (filepath !== filename && !require.cache[filepath]) { 29 | require(filepath); //eslint-disable-line 30 | } 31 | 32 | return filepath; 33 | }); 34 | } 35 | 36 | function loadLayout (filePath) { 37 | layoutCache[filePath] = layoutCache[filePath] 38 | || fs.readFileSync(filePath, 'utf8') 39 | ; 40 | 41 | return layoutCache[filePath]; 42 | } 43 | 44 | /* 45 | * during development we want to "un-require" tags to ensure 46 | * that changes made in components are re-loaded 47 | */ 48 | function unCache () { 49 | tagsLoaded.forEach(function (file) { 50 | delete require.cache[require.resolve(file)]; 51 | }); 52 | tagsLoaded = null; 53 | layoutCache = {}; 54 | } 55 | 56 | /* 57 | * Vision expects this format a compile object that returns a runtime method. 58 | * template is the template name e.g: 'home' or 'dashboard' 59 | * context is the object (2nd argument) passed in to the reply.view method! 60 | */ 61 | function compile (template, compileOpts) { 62 | var baseOpts = Object.assign({}, DEFAULTS, compileOpts); 63 | 64 | return function render (context, renderOpts) { 65 | var layoutFilePath, layoutFileName, content, View, compiledFileRoute; 66 | var mergedOpts = Object.assign({}, baseOpts, renderOpts); 67 | var riotTag = template.split('>')[0].slice(1); 68 | 69 | loadTags(mergedOpts.filename); 70 | compiledFileRoute = mergedOpts.compiledFileRoute || '/bundle.js'; 71 | View = require(mergedOpts.filename); //eslint-disable-line 72 | content = Riot.render(View, context) 73 | + '\n' 74 | + '\n' 75 | + '\n' 77 | ; 78 | if (mergedOpts.layout) { 79 | layoutFileName = mergedOpts.layout === true 80 | ? 'layout.html' 81 | : mergedOpts.layout 82 | ; 83 | layoutFilePath = Path.join(mergedOpts.layoutPath, layoutFileName); 84 | 85 | content = loadLayout(layoutFilePath).replace('<<>>', content); 86 | } 87 | 88 | /* 89 | * Delete the view and layout html from the require cache 90 | * so we don't need to restart the app to see view changes. 91 | * Skipped By default when NODE_ENV=production`. 92 | */ 93 | if (mergedOpts.removeCache) { 94 | unCache(); 95 | } 96 | 97 | return content; 98 | }; 99 | } 100 | 101 | 102 | module.exports = { compile: compile }; 103 | -------------------------------------------------------------------------------- /example/WiP_todo/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Hapi = require('hapi'); 4 | var Vision = require('vision'); 5 | var Inert = require('inert'); 6 | var assert = require('assert'); 7 | var level = require('level'); // https://github.com/Level/level 8 | var path = require('path'); 9 | var db = level(path.join(__dirname, '/db')); 10 | 11 | var HapiRiot = require('../../lib/index.js'); 12 | 13 | var server = new Hapi.Server(); 14 | var port = process.env.PORT || 8000; 15 | 16 | server.connection({ port: port }); 17 | server.register([Vision, Inert], function (err) { 18 | assert(!err); // Halt start if Vision fails to load. 19 | 20 | server.views({ 21 | engines: { tag: HapiRiot }, 22 | relativeTo: __dirname, 23 | path: 'views', 24 | compileOptions: { 25 | layoutPath: path.join(__dirname, 'layout'), 26 | layout: true, 27 | compiledFileRoute: '/bundle.js' 28 | } 29 | }); 30 | 31 | server.route({ 32 | method: 'GET', 33 | path: '/', 34 | handler: function (request, reply) { 35 | db.get('todolist', function (_, value) { 36 | var opts = value ? JSON.parse(value) : {}; 37 | 38 | opts.items = opts.items || []; 39 | opts.path = '/all'; 40 | reply.view('index', opts); 41 | }); 42 | } 43 | }); 44 | 45 | server.route({ 46 | method: 'POST', 47 | path: '/save', 48 | handler: function (request, reply) { 49 | // console.log(' - - - - - - - - - - - - - - - - - '); 50 | // console.log('request.payload', request.payload); 51 | // console.log(' - - - - - - - - - - - - - - - - - '); 52 | 53 | db.get('todolist', function (_, value) { 54 | // console.log("db.get('todolist') err", err, "value:", value); 55 | var titles; 56 | var done = []; 57 | var opts = value ? JSON.parse(value) : {}; 58 | 59 | opts.title = 'My Todo List'; 60 | opts.items = opts.items || []; 61 | // prevent duplicate items 62 | titles = opts.items.map(function (item) { 63 | return item.title; 64 | }); 65 | 66 | if (request.payload.input 67 | && titles.indexOf(request.payload.input) === -1 68 | ) { 69 | opts.items.push({ 70 | title: request.payload.input, 71 | id: opts.items.length 72 | }); 73 | } 74 | // mark totdo items as done 75 | if (request.payload) { 76 | Object.keys(request.payload).forEach(function (k) { 77 | if (k.indexOf('isdone') > -1) { 78 | done.push(parseInt(k.split('isdone-')[1], 10)); 79 | } 80 | }); 81 | 82 | opts.items = opts.items.map(function (item) { 83 | if (item && done.indexOf(item.id) > -1) { 84 | item.done = true; 85 | } 86 | 87 | return item; 88 | }); 89 | } 90 | db.put('todolist', JSON.stringify(opts), function () { 91 | /* opts.items.push({ 92 | title: 'Write Server-Side-Rendered todo-list example in Riot.js', 93 | done: true 94 | }); */ 95 | opts.path = '/all'; 96 | reply.view('index', opts); 97 | }); 98 | }); 99 | } 100 | }); 101 | 102 | server.route({ 103 | method: 'GET', 104 | path: '/active', 105 | handler: function (request, reply) { 106 | db.get('todolist', function (_, value) { 107 | var opts = value ? JSON.parse(value) : {}; 108 | 109 | opts.items = opts.items || []; 110 | opts.items = opts.items.filter(function (item) { 111 | return !item.done; 112 | }); 113 | opts.path = request.path; 114 | reply.view('index', opts); 115 | }); 116 | } 117 | }); 118 | 119 | server.route({ 120 | method: 'GET', 121 | path: '/done', 122 | handler: function (request, reply) { 123 | db.get('todolist', function (_, value) { 124 | var opts = value ? JSON.parse(value) : {}; 125 | 126 | opts.items = opts.items || []; 127 | opts.items.push({ 128 | title: 'Write Server-Side-Rendered todo-list example in Riot.js', 129 | done: true 130 | }); 131 | opts.items = opts.items.filter(function (item) { 132 | return item.done; 133 | }); 134 | console.log('request.path', request.path); // eslint-disable-line 135 | opts.path = request.path; 136 | reply.view('index', opts); 137 | }); 138 | } 139 | }); 140 | 141 | server.route({ 142 | method: 'GET', 143 | path: '/bundle.js', 144 | handler: function (request, reply) { 145 | reply.file(path.join(__dirname, 'bundle.js')); 146 | } 147 | }); 148 | 149 | server.start(function (error) { 150 | assert(!error); // Throw error if server fails to start 151 | console.log('Server is listening at ' + server.info.uri); // eslint-disable-line 152 | }); 153 | }); 154 | 155 | module.exports = server; 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `hapi-riot` 2 | 3 | ***Render Riot Components Server-side*** in your Hapi.js Web Application. 4 | (_supports progressive enhancement on the client so it **Works Everywhere All The TimeTM**_) 5 | 6 | [![Build Status](https://travis-ci.org/dwyl/hapi-riot.svg?branch=master)](https://travis-ci.org/dwyl/hapi-riot) 7 | [![codecov](https://codecov.io/gh/dwyl/hapi-riot/branch/master/graph/badge.svg)](https://codecov.io/gh/dwyl/hapi-riot) 8 | [![Code Climate](https://codeclimate.com/github/dwyl/hapi-riot/badges/gpa.svg)](https://codeclimate.com/github/dwyl/hapi-riot) 9 | [![dependencies Status](https://david-dm.org/dwyl/hapi-riot/status.svg)](https://david-dm.org/dwyl/hapi-riot) 10 | [![devDependencies Status](https://david-dm.org/dwyl/hapi-riot/dev-status.svg)](https://david-dm.org/dwyl/hapi-riot?type=dev) 11 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/hapi-riot/issues) 12 | 13 | ## _Why?_ 14 | 15 | We _love_ the _simplicity_ of Riot.js. 16 | Riot has the "_features_" we _need_ and none of the _complexity_ we don't want. 17 | Riot's clean syntax results in components with ***less code*** than _other_ 18 | "_View Libraries_" or "_Frameworks_" see: http://riotjs.com/compare/ 19 | 20 | Writing less code means you (_the developer/designer_) _**get more done**_, 21 | have _**less to maintain**_ and the _people using your app_ 22 | have to download fewer bytes thus _**saves time/bandwidth**_. 23 | 24 | It's a win-win for _everyone_. 25 | 26 | ### Why _Server-Side_ Rendering Matters ? 27 | 28 | If you render your app on the client/device at least 29 | **_1%_ of your people will see a _blank page_** (no app). 30 | The people who won't _see_ your app are _**your potential users/customers**_ who 31 | for one reason or another don't have the _latest device/browser_, 32 | don't have the most _reliable_ internet connection 33 | or have _dissabled JavaScript_ in their browser for [_**security reasons**_](http://programmers.stackexchange.com/questions/26179/why-do-people-disable-javascript). 34 | 35 | ### The Page _Loads Faster_... 36 | 37 | Pages rendered on the server can send the _absolute minimum_ markup to the client. 38 | This means the "_time to first paint_" is **_always_ faster** than loading a client-side framework 39 | and rendering a page on the client. So, your app/site _is_ and _feels_ faster to people. 40 | 41 | ### Why aren't all apps built this way? 42 | 43 | Good question! _Most_ developers are lazy. They _deny_ the _existence_ of 44 | older browsers/devices as the "minority" convinced that it's "_more work_" 45 | than they _need_ to do. 46 | 47 | We are on a _quest_ to _change_ the perception that _universal_ rendering is 48 | "_more difficult_" and help people write code that _**Works Everywhere All The TimeTM**_ 49 | 50 | #### Read More 51 | 52 | + The 1% figure - https://gds.blog.gov.uk/2013/10/21/how-many-people-are-missing-out-on-javascript-enhancement/ 53 | + Why you _should_ support JS disabled: http://www.punkchip.com/why-support-javascript-disabled/ 54 | 55 | 56 | ## _What?_ 57 | 58 | `hapi-riot` is a views engine to be used with the [_Vision_](https://github.com/hapijs/vision) Plugin. It provide server-side rendering of Riot Components giving rendered html and attaching scripts to rehydrate tags with javascript if possible. 59 | 60 | 61 | > Note if you are totally new to Hapi.js see: 62 | [https://github.com/dwyl/**learn-hapi**](https://github.com/dwyl/learn-hapi) 63 | > And/or if you are new to Riot.js check out: 64 | [https://github.com/dwyl/**learn-riot**](https://github.com/dwyl/learn-riot) 65 | 66 | 67 | ## _How_? 68 | 69 | ### 1. Install 70 | 71 | ```sh 72 | npm install hapi vision hapi-riot --save 73 | ``` 74 | 75 | ### 2. Compile 76 | 77 | Right now we have left you to do the compiling of your tags. You can choose to do this as you like but the most simple way is to write the following into your cmd line: 78 | ``` 79 | riot path/to/your/views/folder output/file/path.js 80 | ``` 81 | For example: `riot example/lib/views bundle.js` -> this will compile your 82 | views and the output the results into a file called `bundle.js` in the root of 83 | your project. It will be a combination of the contents of all of your `.tag` 84 | files. 85 | 86 | > Note for development try adding a watch flag `riot -w example/lib/views bundle.js` to prevent having to compile each time 87 | 88 | Right now we expect all tags to be compiled into one file. 89 | 90 | ### 3. Set up route to compiled file 91 | 92 | `hapi-riot` is just a view engine. You'll need to add a route to your server that can handle requests to your 93 | compiled file, made by **hapi-riot**. Add the following route: 94 | 95 | ```js 96 | server.route({ 97 | method: 'GET', 98 | // this is the same as what you supplied to the view engine in step 4 99 | path: '/your_compiled_file_route.js', 100 | handler: function (request, reply) { 101 | // this is what you specified when compiling in step 2 102 | reply.file(Path.join(__dirname, 'your_compiled_output_file.js')); 103 | } 104 | }); 105 | ``` 106 | 107 | > Note above uses [inert](https://github.com/hapijs/inert) to serve up static files. 108 | 109 | ### 4. Configure Vision Plugin with Hapi-Riot 110 | 111 | You can configure the views engine by passing it `compileOptions` 112 | 113 | ```js 114 | server.views({ // initialise 115 | engines: { 116 | tag: require('hapi-riot') // file should be .tag 117 | }, 118 | relativeTo: __dirname, 119 | path: 'views', // by convention we put our tags in /views dir 120 | compileOptions: { // of this form, see below for meanings 121 | removeCache, 122 | compiledFileRoute, // REQUIRED same as step 3 123 | layoutPath, 124 | layout 125 | } 126 | }); 127 | 128 | ``` 129 | 130 | We have added a few _features_ to _simplify_ our own projects but are not meant to be fit for _everyone_. 131 | 132 | 133 | #### `compiledFileRoute` **REQUIRED** *default: '/bundle.js'* 134 | 135 | This is the oath you specified in step 3 to include javascript within your tags. `hapi-riot` 136 | will then inject a link to your compiled file into your output which makes the 137 | specified methods in your tags available. 138 | 139 | #### `removeCache` *default: `process.env.NODE_ENV === 'production'`* 140 | 141 | While you are _developing_ your app you typically don't want 142 | your views to be _cached_, however, when you deploy your app 143 | by setting `NODE_ENV=production` views will be cached. If for _any_ reason you _want_ to cache your views during development set the value as true; 144 | 145 | #### `layoutPath` *REQUIRED if layout defined* 146 | 147 | The place where your layouts are kept. 148 | 149 | > Note: path does not make use of the relativeTo param given to vision plugin 150 | 151 | #### `layout` *default: undefined* 152 | 153 | Can either be set to `true` in which case we will look for a `layout.html` file or you can specify which ever file you'd like. Can be overridden from `reply.view` to have multiple layouts. 154 | 155 | Specifying a layout allows you to provide a core html page for your riot content where you can include style sheets, other html content and other base scripts. We will inject the riot content into a place holder `<<>>` which much be present in the file. 156 | 157 | An example would be 158 | 159 | ``` 160 | 161 | 162 | 163 | 164 | 165 | <<>> 166 | 167 | 168 | ``` 169 | 170 | 171 | ### 5. Use 172 | 173 | With vision plugin configured and an `index.tag` compiled and place in right directory we should be able to to server side render a page! 174 | ``` 175 | 176 |

{opts.title}

177 |
178 | ``` 179 | 180 | ``` 181 | server.route({ 182 | method: 'GET', 183 | path: '/', 184 | handler: (request, reply) => { // render the view: 185 | reply.view('index', { title: 'My Amazing Title!' }); 186 | } 187 | }); 188 | ``` 189 | 190 | ## Examples 191 | 192 | Run ```npm start``` to see a basic example. 193 | 194 | More/Complete examples are in the [/example directory](https://github.com/dwyl/hapi-riot/tree/master/example). 195 | 196 | If you stuck or need any help just [ask](https://github.com/dwyl/hapi-riot/issues)! 197 | 198 | 199 | ## Lessons Learned & "Gotchas" 200 | 201 | ### 1. At compiling step make sure your bundle.js is in .gitignore 202 | 203 | Add to your `.gitignore` any bundled code in compile step to keep your git history clean. 204 | 205 | ### 2. `console.log` in your `.tag` file ... 206 | 207 | (This is _fairly_ obvious, once you think about it) 208 | if you write a `console.log('your message')` and render it on the server, 209 | it will log out in your server's `stdout` (_i.e. your terminal_). 210 | 211 | ### 3. tag files used as views should be non empty and appropriately wrapped 212 | 213 | When you create a new tag add _something_ to it immediately. e.g: `views/custom.tag` 214 | ```js 215 | 216 |

Content

217 |
218 | ``` 219 | 220 | If you leave a tag empty you will see a strange error when rendering. 221 | 222 | To know which tag to mount we perform ``` template.split('>')[0].slice(1) ``` hence the script mounting your tag on client may be wrong unless you conform to having an appropriate wrapping custom element. 223 | 224 | Also good for them to match filename but less important. 225 | 226 | ### 4. When writing your layout html make sure to add right place holder 227 | 228 | We will be doing a simple find and replace on the characters `<<>>` so make sure there are no conflicts and included in the right place. You can obviously add more html above and below if you so choose. 229 | 230 | ### 5. If not setting the layout param in compile options make sure you have a layout.html file 231 | 232 | If want to use default by using `layout: true` make sure you have a file named `layout.html` in the layout folder path given 233 | 234 | ### 6. Scripts and style stripped out of initial render 235 | 236 | `Riot.render` removes all js and styles. We will reload the tag instance but initially you may lose any styles created with a `