Merge pull request #5651 from chillu/pulls/4.0/restructure-conventions-docs

Frontend build tooling docs cleanup
This commit is contained in:
Ingo Schommer 2016-06-13 08:33:02 +12:00 committed by GitHub
commit 33496d870b
16 changed files with 277 additions and 267 deletions

View File

@ -7,7 +7,7 @@ See our "[Release Process](/contributing/release_process#security-releases) on h
## SQL Injection ## SQL Injection
The [coding-conventions](/getting_started/coding_conventions) help guard against SQL injection attacks but still require developer The [coding-conventions](/contributing/coding_conventions) help guard against SQL injection attacks but still require developer
diligence: ensure that any variable you insert into a filter / sort / join clause is either parameterised, or has been diligence: ensure that any variable you insert into a filter / sort / join clause is either parameterised, or has been
escaped. escaped.

View File

@ -45,8 +45,8 @@ Please make sure you build all files before submitting a pull request!
## Coding Conventions ## Coding Conventions
Please follow our [CSS](/getting_started/css_coding_conventions) Please follow our [CSS](/contributing/css_coding_conventions)
and [JavaScript](/getting_started/javascript_coding_conventions) and [JavaScript](/contributing/javascript_coding_conventions)
coding conventions. coding conventions.
## Sprites ## Sprites

View File

@ -11,6 +11,9 @@ which creates a copy that you can commit to (see github's [guide to "forking"](h
For other modules, our [add-ons site](http://addons.silverstripe.org/add-ons) lists the repository locations, typically using the version control system like "git". For other modules, our [add-ons site](http://addons.silverstripe.org/add-ons) lists the repository locations, typically using the version control system like "git".
If you are modifying CSS or JavaScript files in core modules, you'll need to regenerate some files.
Please check out our [client-side build tooling](build_tooling) guide for details.
<div class="hint" markdown="1"> <div class="hint" markdown="1">
Note: By supplying code to the SilverStripe core team in patches, tickets and pull requests, you agree to assign copyright of that code to SilverStripe Limited, on the condition that SilverStripe Limited releases that code under the BSD license. Note: By supplying code to the SilverStripe core team in patches, tickets and pull requests, you agree to assign copyright of that code to SilverStripe Limited, on the condition that SilverStripe Limited releases that code under the BSD license.
@ -105,7 +108,8 @@ When contributing a backwards incompatible change, you must raise it against the
### The Pull Request Process ### The Pull Request Process
Once your pull request is issued, it's not the end of the road. A [core committer](/contributing/core_committers/) will most likely have some questions for you and may ask you to make some changes depending on discussions you have. Once your pull request is issued, it's not the end of the road. A [core committer](/contributing/core_committers/) will most likely have some questions for you and may ask you to make some changes depending on discussions you have.
If you've been naughty and not adhered to the coding conventions, expect a few requests to make changes so your code is in-line. If you've been naughty and not adhered to the [coding conventions](coding_conventions),
expect a few requests to make changes so your code is in-line.
If your change is particularly significant, it may be referred to the [mailing list](https://groups.google.com/forum/#!forum/silverstripe-dev) for further community discussion. If your change is particularly significant, it may be referred to the [mailing list](https://groups.google.com/forum/#!forum/silverstripe-dev) for further community discussion.
@ -113,7 +117,7 @@ A core committer will also "label" your PR using the labels defined in GitHub, t
#### GitHub Labels #### GitHub Labels
The current GitHub labels are grouped into 5 sections: The current GitHub labels are grouped into five sections:
1. *Changes* - These are designed to signal what kind of change they are and how they fit into the [Semantic Versioning](http://semver.org/) schema 1. *Changes* - These are designed to signal what kind of change they are and how they fit into the [Semantic Versioning](http://semver.org/) schema
2. *Impact* - What impact does this bug/issue/fix have, does it break a feature completely, is it just a side effect or is it trivial and not a bit problem (but a bit annoying) 2. *Impact* - What impact does this bug/issue/fix have, does it break a feature completely, is it just a side effect or is it trivial and not a bit problem (but a bit annoying)
@ -166,7 +170,7 @@ After you have edited the file, GitHub will offer to create a pull request for y
## Check List ## Check List
* Adhere to our [coding conventions](/getting_started/coding_conventions) * Adhere to our [coding conventions](/contributing/coding_conventions)
* If your patch is extensive, discuss it first on the [silverstripe-dev google group](https://groups.google.com/group/silverstripe-dev) (ideally before doing any serious coding) * If your patch is extensive, discuss it first on the [silverstripe-dev google group](https://groups.google.com/group/silverstripe-dev) (ideally before doing any serious coding)
* When working on existing tickets, provide status updates through ticket comments * When working on existing tickets, provide status updates through ticket comments
* Check your patches against the "master" branch, as well as the latest release branch * Check your patches against the "master" branch, as well as the latest release branch
@ -292,262 +296,6 @@ Helpful hint: You can always edit your last commit message by using:
$ git commit --amend $ git commit --amend
## Client-side build tooling
Core JavaScript, CSS, and thirdparty dependencies are managed with the build tooling
described below.
Note this only applies to core SilverStripe dependencies, you're free to manage
dependencies in your project codebase however you like.
### Node.js
The [Node.js](https://nodejs.org) JavaScript runtime is the foundation of our client-side
build tool chain. If you want to do things like upgrade dependencies, make changes to core
JavaScript or SCSS files, you'll need Node installed on your dev environment. Our build
tooling supports the v4.2.x (LTS) version of Node.
You'll likely want to manage multiple versions of Node, we suggest using
[Node Version Manager](https://github.com/creationix/nvm).
### npm
[npm](https://www.npmjs.com/) is the package manager we use for JavaScript dependencies.
It comes bundled with Node.js so should already have it installed if you have Node.
The configuration for an npm package goes in `package.json`. You'll see one in the root
directory of `framework`. As well as being used for defining dependencies and basic package
information, the `package.json` file has some other handy features.
#### npm scripts
The `script` property of a `package.json` file can be used to define command line scripts.
A nice thing about running commands from an npm script is binaries located in
`node_modules/.bin/` are temporally added to your `$PATH`. This means we can use dependencies
defined in `package.json` for things like compiling JavaScript and SCSS, and not require
developers to install these tools globally. This means builds are much more consistent
across development environments.
For more info on npm scripts see
[https://docs.npmjs.com/misc/scripts](https://docs.npmjs.com/misc/scripts)
To run an npm script, open up your terminal, change to the directory where `package.json`
is located, and run `$ npm run <SCRIPT_NAME>`. Where `<SCRIPT_NAME>` is the name of the
script you wish to run.
Here are the scripts which are available in `framework`
Note you'll need to run an `npm install` to download the dependencies required by these scripts.
##### build
```
$ npm run build
```
Runs a Gulp task which builds the core JavaScript files. You will need to run this script
whenever you make changes to a JavaScript file.
Run this script with the `--development` flag to watch for changes in JavaScript files
and automatically trigger a rebuild.
##### lint
```
$ npm run lint
```
Run `eslint` over JavaScript files reports errors.
##### test
```
$ npm run test
```
Runs the JavaScript unit tests.
##### coverage
```
$ npm run coverage
```
Generates a coverage report for the JavaScript unit tests. The report is generated
in the `coverage` directory.
##### css
```
$ npm run css
```
Compile all of the .scss files into minified .css files. Run with the `--development` flag to
compile non-minified CSS and watch for every time a .scss file is changed.
##### sprites
```
$ npm run sprites
```
Generates sprites from the individual image files in `admin/images/sprites/src`.
##### thirdparty
```
$ npm run thirdparty
```
Copies legacy JavaScript dependencies from `node_modules` into the `thirdparty` directory.
This is only required legacy dependencies which are not written as CommonJS or ES6 modules.
All other modules will be included automatically with the `build` script.
##### sanity
```
$ npm run sanity
```
Makes sure files in `thirdparty` match files copied from `node_modules`. You should never commit
custom changes to a library file. This script will catch them if you do :smile:
##### lock
```
$ npm run lock
```
Generates a "shrinkwrap" file containing all npm package versions and writes it to
`npm-shrinkwrap.json`. Run this command whenever a new package is added to `package.json`,
or when updating packages. Commit the resulting `npm-shrinkwrap.json`. This uses a third party
[npm-shrinkwrap](https://github.com/uber/npm-shrinkwrap) library
since the built-in `npm shrinkwrap` (without a dash) has proven unreliable.
### Gulp
[Gulp](http://gulpjs.com/) is the build system which gets invoked by most npm scripts
in SilverStripe. The `gulpfile.js` script is where Gulp tasks are defined.
Here are the Gulp tasks which are defined in `gulpfile.js`
#### build
This is where JavaScript files are compiled and bundled. There are two parts to this which
are important to understand when working core JavaScript files.
##### Babel
[Babel](https://babeljs.io/) is a JavaScript compiler. It takes JavaScript files as input,
performs some transformations, and outputs other JavaScript files. In SilverStripe we use
Babel to transform our JavaScript in two ways.
###### Transforming ES6
ECMAScript 6 (ES6) is the newest version of the ECMAScript standard. It has some great new
features, but the browser support is still patchy, so we use Babel to transform ES6 source
files back to ES5 files for distribution.
To see some of the new features check out
[https://github.com/lukehoban/es6features](https://github.com/lukehoban/es6features)
###### Transforming to UMD
[Universal Module Definition](https://github.com/umdjs/umd) (UMD) is a pattern for writing
JavaScript modules. The advantage of UMD is modules can be 'required' by module loaders
(AMD and ES6 / CommonJS) and can also be loaded via `<script>` tags. Here's a simple example.
```js
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jQuery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('jQuery'));
} else {
// Default browser with no bundling (global is window)
global.MyModule = factory(global.jQuery);
}
}(this, function (jQuery) {
// Module code here
}));
```
The UMD wrapper is generated by Babel so you'll never have to write it manually,
it's handled for you by the build task.
##### Browserify
One of the great new features in ES6 is
[support for native modules](https://github.com/lukehoban/es6features#modules).
In order to support modules, SilverStripe uses
[Browserify](https://github.com/substack/node-browserify) to bundle modules for distribution.
Browserify takes an entry file, creates an abstract syntax tree (AST) by recursively
looking up all the `require` statements it finds, and outputs a bundled JavaScript file which
can be executed in a browser.
In addition to being a concatenated JavaScript file, Browserify bundles contain a lightweight
`require()` implementation, and an API wrapper which allows modules to require each other at
runtime. In most cases modules will bundled together in one JavaScript file, but it's also
possible to require modules bundled in another file, these are called external dependencies.
In this example the `BetterField` module requires `jQuery` from another bundle.
__gulpfile.js__
```js
gulp.task('bundle-a', function () {
return browserify()
.transform(babelify.configure({
presets: ['es2015'] // Transform ES6 to ES5.
}))
.require('jQuery', { expose: 'jQuery' }) // Make jQuery available to other bundles at runtime.
.bundle()
.pipe(source('bundle-a.js'))
.pipe(gulp.dest('./dist'));
});
```
This generates a bundle `bundle-a.js` which includes jQuery and exposed it to other bundles.
__better-field.js__
```js
import $ from 'jQuery';
$('.better-field').fadeIn();
```
__gulpfile.js__
```js
...
gulp.task('bundle-better-field', function () {
return browserify('./src/better-field.js')
.transform(babelify.configure({
presets: ['es2015'] // Transform ES6 to ES5.
}))
.external('jQuery') // Get jQuery from another bundle at runtime.
.bundle()
.pipe(source('bundle-b.js'))
.pipe(gulp.dest('./dist'));
});
```
When Browserify bundles `./src/better-field.js` (the entry file) it will ignore all
require statements that refer to `jQuery` and assume `jQuery` will be available via another
bundle at runtime.
The advantage of using externals is a reduced file size. The browser only needs to download
`jQuery` once (inside `bundle-a.js`) rather than it being included in multiple bundles.
Core dependencies are are bundled and exposed in the `bundle-lib.js` file. Most of the libraries
a CMS developer requires are available a externals in that bundle.
## Some gotchas ## Some gotchas
Be careful not to commit any of your configuration files, logs, or throwaway test files to your GitHub repo. These files can contain information you wouldn't want publicly viewable and they will make it impossible to merge your contributions into the main development trunk. Be careful not to commit any of your configuration files, logs, or throwaway test files to your GitHub repo. These files can contain information you wouldn't want publicly viewable and they will make it impossible to merge your contributions into the main development trunk.

View File

@ -0,0 +1,257 @@
## Client-side build tooling
Core JavaScript, CSS, and thirdparty dependencies are managed with the build tooling
described below.
Note this only applies to core SilverStripe dependencies, you're free to manage
dependencies in your project codebase however you like.
### Node.js
The [Node.js](https://nodejs.org) JavaScript runtime is the foundation of our client-side
build tool chain. If you want to do things like upgrade dependencies, make changes to core
JavaScript or SCSS files, you'll need Node installed on your dev environment. Our build
tooling supports the v4.2.x (LTS) version of Node.
You'll likely want to manage multiple versions of Node, we suggest using
[Node Version Manager](https://github.com/creationix/nvm).
Since we're compiling SVG icons, you'll also need to compile native Node addons,
which requires `gcc` or a similar compiler - see [node-gyp](https://github.com/nodejs/node-gyp#installation)
for instructions on how to get a compiler running on your platform.
### npm
[npm](https://www.npmjs.com/) is the package manager we use for JavaScript dependencies.
It comes bundled with Node.js so should already have it installed if you have Node.
The configuration for an npm package goes in `package.json`. You'll see one in the root
directory of `framework`. As well as being used for defining dependencies and basic package
information, the `package.json` file has some other handy features.
#### npm scripts
The `script` property of a `package.json` file can be used to define command line scripts.
A nice thing about running commands from an npm script is binaries located in
`node_modules/.bin/` are temporally added to your `$PATH`. This means we can use dependencies
defined in `package.json` for things like compiling JavaScript and SCSS, and not require
developers to install these tools globally. This means builds are much more consistent
across development environments.
For more info on npm scripts see
[https://docs.npmjs.com/misc/scripts](https://docs.npmjs.com/misc/scripts)
To run an npm script, open up your terminal, change to the directory where `package.json`
is located, and run `$ npm run <SCRIPT_NAME>`. Where `<SCRIPT_NAME>` is the name of the
script you wish to run.
Here are the scripts which are available in `framework`
Note you'll need to run an `npm install` to download the dependencies required by these scripts.
##### build
```
$ npm run build
```
Runs a Gulp task which builds the core JavaScript files. You will need to run this script
whenever you make changes to a JavaScript file.
Run this script with the `--development` flag to watch for changes in JavaScript files
and automatically trigger a rebuild.
##### lint
```
$ npm run lint
```
Run `eslint` over JavaScript files reports errors.
##### test
```
$ npm run test
```
Runs the JavaScript unit tests.
##### coverage
```
$ npm run coverage
```
Generates a coverage report for the JavaScript unit tests. The report is generated
in the `coverage` directory.
##### css
```
$ npm run css
```
Compile all of the .scss files into minified .css files. Run with the `--development` flag to
compile non-minified CSS and watch for every time a .scss file is changed.
##### sprites
```
$ npm run sprites
```
Generates sprites from the individual image files in `admin/images/sprites/src`.
##### thirdparty
```
$ npm run thirdparty
```
Copies legacy JavaScript dependencies from `node_modules` into the `thirdparty` directory.
This is only required legacy dependencies which are not written as CommonJS or ES6 modules.
All other modules will be included automatically with the `build` script.
##### sanity
```
$ npm run sanity
```
Makes sure files in `thirdparty` match files copied from `node_modules`. You should never commit
custom changes to a library file. This script will catch them if you do :smile:
##### lock
```
$ npm run lock
```
Generates a "shrinkwrap" file containing all npm package versions and writes it to
`npm-shrinkwrap.json`. Run this command whenever a new package is added to `package.json`,
or when updating packages. Commit the resulting `npm-shrinkwrap.json`. This uses a third party
[npm-shrinkwrap](https://github.com/uber/npm-shrinkwrap) library
since the built-in `npm shrinkwrap` (without a dash) has proven unreliable.
### Gulp
[Gulp](http://gulpjs.com/) is the build system which gets invoked by most npm scripts
in SilverStripe. The `gulpfile.js` script is where Gulp tasks are defined.
Here are the Gulp tasks which are defined in `gulpfile.js`
#### build
This is where JavaScript files are compiled and bundled. There are two parts to this which
are important to understand when working core JavaScript files.
##### Babel
[Babel](https://babeljs.io/) is a JavaScript compiler. It takes JavaScript files as input,
performs some transformations, and outputs other JavaScript files. In SilverStripe we use
Babel to transform our JavaScript in two ways.
###### Transforming ES6
ECMAScript 6 (ES6) is the newest version of the ECMAScript standard. It has some great new
features, but the browser support is still patchy, so we use Babel to transform ES6 source
files back to ES5 files for distribution.
To see some of the new features check out
[https://github.com/lukehoban/es6features](https://github.com/lukehoban/es6features)
###### Transforming to UMD
[Universal Module Definition](https://github.com/umdjs/umd) (UMD) is a pattern for writing
JavaScript modules. The advantage of UMD is modules can be 'required' by module loaders
(AMD and ES6 / CommonJS) and can also be loaded via `<script>` tags. Here's a simple example.
```js
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jQuery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('jQuery'));
} else {
// Default browser with no bundling (global is window)
global.MyModule = factory(global.jQuery);
}
}(this, function (jQuery) {
// Module code here
}));
```
The UMD wrapper is generated by Babel so you'll never have to write it manually,
it's handled for you by the build task.
##### Browserify
One of the great new features in ES6 is
[support for native modules](https://github.com/lukehoban/es6features#modules).
In order to support modules, SilverStripe uses
[Browserify](https://github.com/substack/node-browserify) to bundle modules for distribution.
Browserify takes an entry file, creates an abstract syntax tree (AST) by recursively
looking up all the `require` statements it finds, and outputs a bundled JavaScript file which
can be executed in a browser.
In addition to being a concatenated JavaScript file, Browserify bundles contain a lightweight
`require()` implementation, and an API wrapper which allows modules to require each other at
runtime. In most cases modules will bundled together in one JavaScript file, but it's also
possible to require modules bundled in another file, these are called external dependencies.
In this example the `BetterField` module requires `jQuery` from another bundle.
__gulpfile.js__
```js
gulp.task('bundle-a', function () {
return browserify()
.transform(babelify.configure({
presets: ['es2015'] // Transform ES6 to ES5.
}))
.require('jQuery', { expose: 'jQuery' }) // Make jQuery available to other bundles at runtime.
.bundle()
.pipe(source('bundle-a.js'))
.pipe(gulp.dest('./dist'));
});
```
This generates a bundle `bundle-a.js` which includes jQuery and exposed it to other bundles.
__better-field.js__
```js
import $ from 'jQuery';
$('.better-field').fadeIn();
```
__gulpfile.js__
```js
...
gulp.task('bundle-better-field', function () {
return browserify('./src/better-field.js')
.transform(babelify.configure({
presets: ['es2015'] // Transform ES6 to ES5.
}))
.external('jQuery') // Get jQuery from another bundle at runtime.
.bundle()
.pipe(source('bundle-b.js'))
.pipe(gulp.dest('./dist'));
});
```
When Browserify bundles `./src/better-field.js` (the entry file) it will ignore all
require statements that refer to `jQuery` and assume `jQuery` will be available via another
bundle at runtime.
The advantage of using externals is a reduced file size. The browser only needs to download
`jQuery` once (inside `bundle-a.js`) rather than it being included in multiple bundles.
Core dependencies are are bundled and exposed in the `bundle-lib.js` file. Most of the libraries
a CMS developer requires are available a externals in that bundle.

View File

@ -0,0 +1,5 @@
# Coding Conventions
* [PHP Coding Conventions](php_coding_conventions)
* [CSS Coding Conventions](css_coding_conventions)
* [JavaScript Coding Conventions](javascript_coding_conventions)

View File

@ -42,5 +42,5 @@ and can be checked locally via `npm run lint`.
## Related ## Related
* [PHP Coding Conventions](/getting_started/coding_conventions) * [PHP Coding Conventions](/contributing/php_coding_conventions)
* [CSS Coding Conventions](/getting_started/css_coding_conventions) * [CSS Coding Conventions](/contributing/css_coding_conventions)

View File

@ -64,6 +64,6 @@ consider porting them over into the new structure. Otherwise, follow these conve
## Related ## Related
* [PHP Coding Conventions](/getting_started/coding_conventions) * [PHP Coding Conventions](/contributing/php_coding_conventions)
* [JavaScript Coding Conventions](/getting_started/javascript_coding_conventions) * [JavaScript Coding Conventions](/contributing/javascript_coding_conventions)
* [Browser support](/getting_started/server_requirements/) * [Browser support](/getting_started/server_requirements/)

View File

@ -458,5 +458,5 @@ which are licensed under BSD (see [license](http://framework.zend.com/license)).
## Related ## Related
* [JavaScript Coding Conventions](/getting_started/javascript_coding_conventions) * [JavaScript Coding Conventions](/contributing/javascript_coding_conventions)
* [Reference: CMS Architecture](/developer_guides/customising_the_admin_interface/cms_architecture) * [Reference: CMS Architecture](/developer_guides/customising_the_admin_interface/cms_architecture)