aq-web-front
v0.1.33
Published
A compilation framework to allow coding web frontends in a modern style.
Downloads
48
Maintainers
Readme
AQ Web Front
AWF is a compilation framework to allow coding web frontends in a modern style.
Integration of some of the currently best frontend frameworks: Babel, React and Stylus.
Features
- ES2015 provided by Babel (not including features requiring pollyfill)
- CSS preprocessing provided by Stylus (nib import allowed)
- Merge source files according to imports
- Listen for data changes by using BoundObject
- Best effort to generate legacy IE compatible JS code (will automatically load ES5-Shim, ES5-Sham, and JSON3)
- for...in on arrays will only traverse array members
- Easy import for popular JS libraries: lodash, jQuery and more (React and ReactDOM are automatically imported if when use of JSX exists)
- Source map gereration for both js and css artifacts
- Code will be called after the DOM is ready
Installation
npm install -g aq-web-front
Usage
Initialize project directory, generate a configuration file:
$> cd 'Project Root/'
$> mkdir app
$> cd app
$> awf init
Begin auto progressive build:
$> cd 'Project Root/app'
$> awf
Running awf
will start watching changes in the app
directory, and generate the
following files in Project Root/
: app.js, app.css.
TIP:
- The name of the generated files will be the same as the watched directory.
i.e. watching in
home
directory will generate home.js and home.css. - Although you have to run
awf init
right at the directory where source files are watched, runningawf
is not required to be so. You may run it anywhere, and the framework will scan child directories in search of configuration files, or traverse up the directory tree if none were found. Watching will start at where existing configuration files were found.
Directory Structure
This is just an example of how things might work, actual usage may vary.
Project Root/ --+-- app/ -----------+-- awf.conf
| |
+-- @ app.js +-- ClassA/ ---------+-- index.js
| | |
+-- @ app.css +-- ClassB.js +-- View.jsx
| | |
| +-- other sources +-- Style.styl
| |
| +-- @ _build/
|
+-- index.html (or other AWF unrelated files)
TIP:
- Items marked
@
are generated by this framework - As described in the usage description,
the names of
app.js
andapp.css
will follow the name ofapp
directory _build
directory is used for storing progressive compile cache and source maps. You may change this to another name by editing the configuration file.- Delete
_build
directory if you want a full and clean recompile. - You may want to add
_build/
into your.gitignore
or other version control ignore files to keep repo clean.
Configuration
Configuration is required before building. By calling awf init
, a configuration file
named awf.conf
is generated in the current directory. By default, awf init
will take
you through some steps to setup the initial preferences. You may call awf init --default
or awf init -d
to generate a configuration file with all default values.
A configuration file is basically a YAML file contain these setups:
- Debug mode
true
: when off, source maps will not be gernerated and all non-error console outputs will be hidden. When on, debug versions of external libraries will be loaded if available. - Build Directory
_build
: where compile caches and source maps are stored. - External libraries
non-inline cdnjs
: libraries that you may import, providing it's url and whether it should be inlined. Inlining a library means that the content of the script will be written directly into the generated artifact rather than loading it during runtime.
Examples
- Basic Usage
- ES2015
- Module import and export
- JSX classes
- Stylus integration
- BoundObject
- lodash, jQuery, and more
- A fully working example: Grocery list
Basic usage
index.html
<!DOCTYPE html>
<html>
<head>
<title>AWF Basic Usage</title>
<link href="app.css" rel="stylesheet" type="text/css"/>
<script src="app.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
app/BasicUsage.js
console.log('It works'); // output to console
ReactDOM.render(<div>It works</div>, document.body); // output to DOM
Note:
document.body
will be available in all popular browsers including IE6- React deprecates rendering to document.body, but if you didn't receive a warning message, you're probably not in debug mode. Debug mode can be toggled by editing configuration file.
- When you debug mode, source maps will allow you to be able to trace where the console outputs are located in the source files. Some browsers (such as safari) will cache source map files, and may require manual clean up.
ES2015
app/ES2015.js
// class definition and inheritance
class A {
whoAmI() {
return 'A';
}
}
class B extends A {
whoAmI() {
return 'B : ' + super.whoAmI();
}
}
var b = new B();
console.log(b.whoAmI()); //$> B : A
// for of iteration (AWF fixed this feature to make it compatible with IE6)
var str = '';
for (var num of [5, 4, 3, 2, 1]) {
str += num + ' - ';
}
console.log(str); //$> 5 - 4 - 3 - 2 - 1 -
// function argument default values
function add(a, b=1) {
return a + b;
}
console.log(add(2, add(1))); //$> 4
This is an example of how you can use some of the language features specified in EcmaScript 6. For more information checkout the learn ES2015 section of the Babel project.
Please beware that features requiring pollyfill will not be resolved automatically. To use them, you must manually load the scripts required, but in this case AWF will not be responsible for compatibility issues on legacy browsers.
Module import and export
app/A.js
class A { // symbol with the same name of the source file is exported by default
whoAmI() {
return 'A';
}
}
app/B/index.js (when named as index, this module is imported as directory path, i.e. 'B')
import '../A'; // will be parsed as `import A from '../A';`
export default ClassB extends A {
whoAmI() {
return 'B : ' + super.whoAmI();
}
}
app/subdir/C.js
import Class from 'B'; // when not starting with './' or '../', the path will be
// resolved relative to app diretory, so this is the same
// as writing `import '../B'`
var b = new Class();
console.log(b.whoAmI()); //$> B : A
JSX classes
app/Template.jsx
<div>
<button if={this.state.showBtn} onClick={this.onBtnClick}>click me</button>
</div>
app/Control.js
import './Template';
class Control extends Template {
componentWillMount() {
this.setState({showBtn:true});
}
onBtnClick() {
alert('Button clicked!');
this.setState({showBtn:false});
}
}
app/Body.jsx
import 'Control'; // You may import in a jsx file just as how you would do in a js file
<div>
<Control/>
</div>
app/Main.js
import 'Body';
class Main extends React.Component { // an example of how to define a React component
// directly in js code
render() {
return <Body/>;
}
}
ReactDOM.render(<Main/>, document.body);
A jsx file generates a module exporting a React class rendering the contents of of the jsx file.
TIP: React and ReactDOM are auto imported when any jsx syntax exists in the source file
Stylus integration
app/Style.styl
@import 'nib'; // nib is available to import
color: #00F
.message
background: #F00
app/Body.jsx
import 'Style';
<div className={Style}>
<div className="message">
Hello World
</div>
</div>
Stylus files will construct a module which can be imported and used as a class name. Stylus style sheets will never be applied globally, it will only affect elements with corresponding class name.
BoundObject
var obj = BoundObject.create();
BoundObject(obj).listen((e) => {console.log(e);})
e.x = 1;
//$> {obj:obj, key:"x", newValue:1, oldValue:undefined}
var arr = [];
BoundObject.create(arr);
BoundObject(arr).listen((e) => {console.log(e);})
arr.push(1);
//$> {obj:arr, key:"length", newValue:1, oldValue:0}
With BoundObject, you'll be able to watch for changes on the object. When a BoundObject is assigned as a property of another BoundObject, change events will propagate to the parent.
class ExampleView extends React.Component {
componentWillMount() {
this.obj = BoundObject.create({
counter: 0
});
setInterval(() => this.obj.counter++, 1000);
}
render() {
return <div>{this.obj.counter}s has elapsed</div>
}
}
React.Component
has been modified to issue forceUpdate
whenever a member BoundObject has changed.
lodash, jQuery, and more
import $ from 'jQuery';
import _ from 'lodash';
import _ from 'underscore';
import 'chart';
import Promise from 'bluebird';
You'll be able to use these popular libraries in your project just by a line of import. Which and how libraries are loaded depends on configuration. Other external libraries can made available be by editing the library section of the configuration file.
A fully working example: Grocery list
Code along with compiled result are located in the example directory of the repo.
Caveat
- Do not name variable or object member starting with
$$$AWF$$$
. Doing so might break the framework. - Do not define function or variable named
require
, it will break the import feature. - Do not put anything yourself in the
_build
directory if you don't want to mess up the auto-build. - Module names do not include anything after
.
,app/Mod.A.js
should be imported asMod
. Soapp/Mod.A.js
will conflict withapp/Mod.B.jsx
, and will cause an link error. - Circular import is not allowed. A link error will occur if done so.
- When using stylus, the image and other urls should be relative to the source file.
- Although the generated artifacts are compact, they are not minimized. You may save some extra KB by using uglify.
- This framework is still under development, don't use it for anything serious yet