2019-05-21 14:11:40 +02:00
# 🦉 Tooling 🦉
2019-06-09 17:25:14 +02:00
## Content
2019-06-09 16:56:27 +02:00
2019-06-09 17:25:14 +02:00
- [Overview ](#overview )
- [Playground ](#playground )
- [Benchmarks ](#benchmarks )
2019-10-04 22:12:56 +02:00
- [Single File Component ](#single-file-component )
2019-12-01 21:54:40 +01:00
- [Debugging Script ](#debugging-script )
2019-06-09 16:56:27 +02:00
2019-06-09 17:25:14 +02:00
## Overview
2019-06-09 16:56:27 +02:00
2019-06-09 17:25:14 +02:00
To help work with/improve/learn OWL, there are a few extras tools/settings.
2019-06-09 16:56:27 +02:00
2019-06-09 17:25:14 +02:00
- development mode: enable better error reporting for the developer
- a playground application: a space to experiment and learn Owl.
- a benchmarks application: allow comparison with a few common frameworks
2019-06-09 16:56:27 +02:00
2019-06-09 17:25:14 +02:00
The two applications are available in the `tools/` folder, and can be accessed
by using a static http server. A simple python
server is available in `server.py` . There is also a npm script to start it:
`npm run tools` (and its version with a watcher: `npm run tools:watch` ).
2019-05-21 14:11:40 +02:00
2019-06-09 17:25:14 +02:00
## Playground
The playground is an important application designed to help learning and
experimenting with Owl. The last published version of Owl can be tested [online ](https://odoo.github.io/owl/playground/ ).
It is an application similar to `jsFiddle` , but specialized for Owl: there are
three tabs (`js` , `css` and `xml` ), and a simple button `Run` to execute that
code in an iframe.
2019-06-09 16:56:27 +02:00
## Benchmarks
2019-06-09 17:25:14 +02:00
Note: This is more an internal tool, useful for people working on Owl.
2019-06-09 16:56:27 +02:00
The benchmarks application is a very small application, implemented in different
2019-06-09 17:25:14 +02:00
frameworks, and in different versions of Owl. This is a simple internal tool,
2019-06-09 16:56:27 +02:00
useful to compare various performance metrics on some tasks.
2019-09-26 17:04:42 +02:00
## Single File Component
2019-10-26 08:55:38 +02:00
It is very useful to group code by feature instead of by type of file. It makes
it easier to scale application to larger size.
2019-12-19 21:54:35 +01:00
To do so, Owl has two small helpers that make it easy to define a
template or a stylesheet inside a javascript (or typescript) file: the
[`xml` ](reference/tags.md#xml-tag ) and [`css` ](reference/tags.md#css-tag )
helper.
2019-10-26 08:55:38 +02:00
2019-12-19 21:54:35 +01:00
This means that the template, the style and the javascript code can be defined in
the same file. For example:
2019-09-26 17:04:42 +02:00
``` js
2019-10-26 08:55:38 +02:00
const { Component } = owl ;
2019-12-19 21:54:35 +01:00
const { xml , css } = owl . tags ;
2019-10-26 08:55:38 +02:00
2019-09-26 17:04:42 +02:00
// -----------------------------------------------------------------------------
// TEMPLATE
// -----------------------------------------------------------------------------
const TEMPLATE = xml /* xml */ `
2019-12-19 21:54:35 +01:00
<div class="main">
2019-09-26 17:04:42 +02:00
<Sidebar/>
<Content />
</div> ` ;
2019-12-19 21:54:35 +01:00
// -----------------------------------------------------------------------------
// STYLE
// -----------------------------------------------------------------------------
const STYLE = css /* css */ `
.main {
display: grid;
grid-template-columns: 200px auto;
}
` ;
2019-09-26 17:04:42 +02:00
// -----------------------------------------------------------------------------
// CODE
// -----------------------------------------------------------------------------
2019-12-19 21:54:35 +01:00
class Main extends Component {
2019-09-26 21:56:01 +02:00
static template = TEMPLATE ;
2019-12-19 21:54:35 +01:00
static style = STYLE ;
2019-09-26 21:56:01 +02:00
static components = { Sidebar , Content } ;
2019-09-26 17:04:42 +02:00
2019-09-26 21:56:01 +02:00
// rest of component...
2019-09-26 17:04:42 +02:00
}
2019-09-26 21:56:01 +02:00
```
2019-10-26 08:55:38 +02:00
Note that the above example has an inline xml comment, just after the `xml` call.
This is useful for some editor plugins, such as the VS Code addon
`Comment tagged template` , which, if installed, add syntax highlighting to the
content of the template string.
2019-12-01 21:54:40 +01:00
## Debugging Script
## Debugging
Non trivial applications become quickly more difficult to understand. It is then
useful to have a solid understanding of what is going on. To help with that,
logging useful information is extremely valuable. There is a [javascript file ](../tools/debug.js ) which can be evaluated in an application.
Once it is executed, it will log a lot of information on each component main hooks. The following code is a minified version to make it easier to copy/paste:
```
2019-12-06 12:02:06 +01:00
function debugOwl(t,n){let e,o="[OWL_DEBUG]";function s(t){let n=JSON.stringify(t||{});return n.length>200&&(n=n.slice(0,200)+"..."),n}if(Object.defineProperty(t.Component,"current",{get:()=>e,set(i){e=i;const r=i.constructor.name;if(n.componentBlackList&&n.componentBlackList.test(r))return;if(n.componentWhiteList&&!n.componentWhiteList.test(r))return;let l;Object.defineProperty(e,"__owl__",{get:()=>l,set(e){!function(e,i,r){let l=`${i}<id=${r}>`,c=t=>console.log(`${o} ${l} ${t}`),u=t=>(!n.methodBlackList||!n.methodBlackList.includes(t))&&!(n.methodWhiteList&&!n.methodWhiteList.includes(t));u("constructor")&&c(`constructor, props=${s(e.props)}`);u("willStart")&&t.hooks.onWillStart(()=>{c("willStart")});u("mounted")&&t.hooks.onMounted(()=>{c("mounted")});u("willUpdateProps")&&t.hooks.onWillUpdateProps(t=>{c(`willUpdateProps, nextprops=${s(t)}`)});u("willPatch")&&t.hooks.onWillPatch(()=>{c("willPatch")});u("patched")&&t.hooks.onPatched(()=>{c("patched")});u("willUnmount")&&t.hooks.onWillUnmount(()=>{c("willUnmount")});const d=e.__render.bind(e);e.__render=function(...t){c("rendering template"),d(...t)};const h=e.render.bind(e);e.render=function(...t){const n=e.__owl__;let o="render";return n.isMounted||n.currentFiber||(o+=" (warning: component is not mounted, this render has no effect)"),c(o),h(...t)};const p=e.mount.bind(e);e.mount=function(...t){return c("mount"),p(...t)}}(i,r,(l=e).id)}})}}),n.logScheduler){let n=t.Component.scheduler.start,e=t.Component.scheduler.stop;t.Component.scheduler.start=function(){this.isRunning||console.log(`${o} scheduler: start running tasks queue`),n.call(this)},t.Component.scheduler.stop=function(){this.isRunning&&console.log(`${o} scheduler: stop running tasks queue`),e.call(this)}}if(n.logStore){let n=t.Store.prototype.dispatch;t.Store.prototype.dispatch=function(t,...e){return console.log(`${o} store: action '${t}' dispatched. Payload: '${s(e)}'`),n.call(this,t,...e)}}}
2019-12-03 14:12:23 +01:00
debugOwl(owl, {
2019-12-01 21:54:40 +01:00
// componentBlackList: /App/, // regexp
// componentWhiteList: /SomeComponent/, // regexp
// methodBlackList: ["mounted"], // list of method names
// methodWhiteList: ["willStart"], // list of method names
logScheduler: false, // display/mute scheduler logs
logStore: true, // display/mute store logs
2019-12-02 17:13:12 +01:00
});
2019-12-01 21:54:40 +01:00
```
Note that it is certainly useful to run this code at some point in an application,
just to get a feel of what each user action implies, for the framework.