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:
gt; cd 'Project Root/'
gt; mkdir app
gt; cd app
gt; awf init
Begin auto progressive build:
gt; cd 'Project Root/app'
gt; 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, running awf 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.
As described in the usage description,
the names of app.js and app.css will follow the name of app 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.
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()); //gt; 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); //gt; 5 - 4 - 3 - 2 - 1 -
// function argument default values
function add(a, b=1) {
return a + b;
}
console.log(add(2, add(1))); //gt; 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()); //gt; B : A
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.
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.
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 as Mod.
So app/Mod.A.js will conflict with app/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