Commit 6e242f9b authored by Philipp Nowinski's avatar Philipp Nowinski
Browse files

Merge branch 'v4.0' into 'master'

V4.0



See merge request !3
parents cab284f0 6229c2ea
# http://editorconfig.org
root = true
[*]
indent_style = tab
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
node_modules/
coverage
.idea
*.iml
node_modules
language: node_js
node_js:
- '0.10'
before_install:
- currentfolder=${PWD##*/}
- if [ "$currentfolder" != 'generator-sgalinski' ]; then cd .. && eval "mv $currentfolder generator-sgalinski" && cd generator-sgalinski; fi
{}
\ No newline at end of file
# License
## Dual License
### Non-commercial usage
This software is made available for any non-commercial project under the terms and conditions of the MIT-License.
#### MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### Commercial usage
The usage of this software for commercial projects, requires the payment of a small fee. Please contact us under stefan@sgalinski.de
if you wish to use this software in a commercial context.
\ No newline at end of file
......@@ -2,19 +2,8 @@
# generator-gulp-sgalinski
> [Yeoman](http://yeoman.io) generator
> **Note: major changes with version 3.0.0**
> If you have used previous versions of this generator, there are some things to notice:
> The asset-paths.json files are no longer needed. The generator now follows a convention over configuration approach
> and assumes, that your extensions follow the same directory structure. Also, the standalone mode has been removed.
> The whole purpose of this generator is now to scaffold a frontend build process for TYPO3 projects with Extbase Extensions.
## Installation
* [Install Node](docs/INSTALL-NODE.md)
To use the sgalinski-generator you need to have node and npm installed. Furthermore, you should have
yeoman, gulp and bower installed globally. To do so, simply run
......@@ -37,122 +26,163 @@ To run the generator, navigate to the directory you want to create your project
yo gulp-sgalinski
```
## Updating
This will generate all the files you need to run the toolchain, including a config.json file which you will have to adapt to your needs.
Here is what you get in detail:
* gulp | this folder contains the gulp tasks, split into several files, as well as the config.json
* gulpfile.js | The entry point for gulp
* package.json | The package file that contains all needed Node dependencies
* npm-shrinkwrap.json | This file contains all required dependencies, locked down to a specific version number ([learn more](https://docs.npmjs.com/cli/shrinkwrap))
* install.sh | you can execute this file to ensure a proper installation of the toolchain. It will set up the correct version of Node, Gulp and the toolchain.
* .editorconfig | [Editorconfig](http://editorconfig.org/) is a great common way to synchronize editor settings across projects and IDEs/Editors. You can simply remove it, if you don't want to use it.
* .jshintrc | The configuration file for jshint
* .scss-lint.yml | The configuration file for Scss-Linters
### Useful tasks
#### Updating / Installing the toolchains dependencies
If you want to update the Toolchain for an existing project, simply run the generator again inside your projects root.
The generator will ask you before overwriting existing files. Keep an eye on the release notes to see if there are
any breaking changes.
> This task will also be executed by the install.sh script
Starting with v3.2.1, the generator will add an entry to the package.json that will provide you with the version number
of the generator your projects setup has been generated with.
In order for the toolchain to work, you need to install all its dependencies. To do so, you can simply run the update task
(this will also work for the initial installation). Please note that you need to go to the website root
(e.g. web/website-base.dev/) in order to execute this command.
### Further documentation
```bash
npm run-script toolchain:update
```
* [Sprite engine](docs/SPRITE-ENGINE.md)
* [Inline SVG](docs/INLINE-SVG.md)
This task will delete all previously installed dependencies and pull in the new ones.
#### TYPO3 projects
The purpose of this generator is to scaffold a frontend build process for TYPO3 projects with Extbase Extensions. This
assumes, that your code is organized in extension folders under typo3conf/ext and that all extensions follow the same
directory structure. The generator will ask you for the paths to the asset files relative to the extensions folder.
#### Upgrading the toolchain
##### Running a specific task
If you just want to run a specific task for a specific extension, run
> **Caution!**
> This task is only meant for finishing up a new release of the toolchain itself.
To upgrade all dependencies and rewrite the npm-shrinkwrap, run the following command:
```bash
gulp [taskname] --ext [extensionname]
npm run-script toolchain:upgrade
```
E.g. if you want to run the CSS task for an extension called 'acme_base', run
The upgrade task will delete all dependencies, remove the current shrinkwrap and then install the new dependencies (as stated in package.json) and create a new shrinkwrap.
If you run this task, make sure that you know what you're doing, as updating dependencies can break stuff if not propperly tested!
## Configuration
To adjust the toolchain to a certain project, there is a [config.json](app/templates/gulp/config.json) file where the following options can be configured:
### directories
Holds the paths to the css, sass, javascript, images, sprites and inline-svgs, relative to the extensions root.
### abovethefold
Configuration for the critical path css.
* template: *path to the src template*
* dest: *path to the destination*
### js
* libraryPaths: *additional locations that should be searched when resolving CommonJS requires*
* excludeFromQa: *glob patterns with locations that hold JavaScript that does not need to be linted (vendor stuff)
### images
* optimize: *locations of user uploaded images that should be optimized*
### extensions
A list of extensions that should be included in the watch task. Please note, that the very first extension in this list is expected to be your project_theme.
## Usage
You can run a specific task on a specific component, or start a watcher that will fire up BrowserSync and run tasks when
source files change. Extensions that will be watched are defined in [config.json](gulp/config.json).
If you run a specific task, you need to specify the extension you want the task to run on with the --ext parameter.
```bash
gulp css --ext acme_base
gulp css --ext project_base
```
You must specify the extension name here, to tell gulp which SASS files you want to compile.
##### Watching the whole project
By running
There are a few available tasks you need to remember:
### default/watch task
```bash
gulp
```
you will get a development environment with BrowserSync and some watchers that will automatically trigger tasks when you change sourcefiles. If you are not familliar with [BrowserSync](http://www.browsersync.io/), you should definitely check it out.
BrowserSync will basically start up a server and provide you with a URL which points to your project. BrowserSync will be set up with a proxy that tunnels request to your development URL. You can change this URL inside gulp/browser-sync.js. BrowserSync will also disable the TYPO3 cache and the ([scriptmerger extension](http://typo3.org/extensions/repository/view/scriptmerger)) for every request, by setting query string parameters. Apart from the livereload functionallity, BrowserSync offers some other cool features like syncing Mouse- and Keyboardevents. Since version 2.0.0, there is also a UI with a lot more to discover. You should read about this on the BrowserSync website.
Once the default tasks started and BrowserSync is ready to serve your files, all changes you make to you CSS and JavaScript files will automatically injected into the browser, without reloading the site. Gulp will automatically figure out the extension you made changes to and pass the information to the corresponding task.
#### Available gulp tasks
* default
* [command: 'gulp']
* The default task will be triggered by just calling 'gulp' without a specific task name. It will start BrowserSync and watchers for your CSS and JavaScript.
* css
* [command: 'gulp css']
* The css task will compile your sass files to css and run a bunch of additional processes on them.
* It will run the included sprite-engine ([learn how to use it](docs/SPRITE-ENGINE.md)).
* It will resolve css-width and css-height functions ([learn how to use them](https://www.npmjs.com/package/gulp-css-image-dimensions)).
* It will autoprefix your css.
* It will resolve css @import-statements to avoid additional requests.
* It will generate sourcempas for your css files.
* It will log the filesize of the generated css to the console. You can specify a limit to get warnings if this limit is exceeded.
* It will minify your css.
* javascript
* [command: 'gulp javascript']
* The javascript task runs jshint on your JS files. It also runs
[browserify](http://browserify.org/) on them and uglify the result.
* images
* [command: 'gulp images']
* The images task will optimize (lossless) all images inside you images directory. This is not part of the watch
task, so you have to start it manually.
* [command: 'gulp images-fileadmin']
* Runs the image optimization on all images inside fileadmin and uploads. You might want to run this task on a regular
basis to compress user uploaded content.
* browser-sync
* [command: 'gulp browser-sync']
* BrowserSync starts a webserver with built-in code sync and action sync. Refer to
[the BrowserSync website](http://www.browsersync.io/) to learn more about it. BrowserSync will also add query string
parameters to every request that disable the TYPO3 cache and the ([scriptmerger extension](http://typo3.org/extensions/repository/view/scriptmerger)).
#### config files
The gulp-sgalinski generator will generate the following config files:
* .editorconfig
* [Editorconfig](http://editorconfig.org/) is a great common way to synchronize editor settings across projects and
IDEs/Editors. You can simply remove it, if you don't want to use it.
* .jshintrc
* This is where you can define all rules JsHint will apply to your code. If you delete this file, JsHint will use
the standard settings. This file should also work for instances of JsHint that are built into your Editor.
* .scss-lint.yml
* A configuration file for SCSS-Linters.
* gulp/config.json
* This is where the paths to your asset files, relative to the extension folder are defined, as well as the list
of extension names you want gulp to watch for changes.
* package.json [mandatory]
* The package.json file is the manifest for every node.js module. Since gulp is written in node, you will need this
file. This is where all used node modules (e.g. every gulp task is a node module) are defined as dependencies. They
will get installed from the NPM registry when you run 'npm install' inside your project root (the generator will run
'npm install' and 'bower install' automatically for you as its last step).
#### What to check in?
There are different opinions on which files should be under version control. We recommend to put the following files
on your ignorelist (.gitignore, .svnignore, etc.):
* node_modules
* This folder can be quite heavy and its contents can differ depending on you Operating System. The recommended way
is to check in the package.json and run 'npm install' on every new checkout.
## Changelog
* 2015-07-21   v3.2.1   Update README; add toolchain version number to package.json
* 2015-07-21   v3.2.0   update to sprity; performance optim.; plugin updates; new config files
* 2015-06-04   v3.1.0   add inline-svg plugin
* 2015-05-21   v3.0.0   Remove standalone mode; get rid of asset-path.json; add check-filesize-plugin
* 2015-02-22   v2.1.0   add cache and scriptmerger deactivation via query string params
* 2015-02-15   v2.0.0   get rid of compass + update browsersync + add global watcher
* 2015-01-19   v1.1.0   major changes to the scaffolded gulp tasks + massive README
* 2015-01-13   v1.0.0   add livereload as browsersync alternative [first stable version]
* 2015-01-12   v0.1.0   release
## License
MIT
Starts a project wide watcher that will trigger the css/javascript task when you change any .scss, or .js-file and opens
the website in your browser, as a browsersync session (changed js and css will automatically get injected when recompiled).
*Hint:* If you already have a browsersync instance open in your browser, you can pass the argument -s to restart the session without opening a browser.
### sprite task
```bash
gulp sprites --ext [extensions name]
```
Triggers sprite generation inside the given directory.
Assumptions:
* all sprite images are inside images/sprites, relative to the given path.
* all sprite images are PNGs.
* there is a sass directory, next to the images folder.
This task will generate a png inside the images folder, containing all the sprites and a .scss file inside the sass
folder, which will provide the necessary mixins. To use the sprites inside your SASS code, import the _sprite.scss file.
You can then use the following mixins:
```scss
// will output css for a sprite image 'box.png'
.element {
@sprite ($box);
}
```
The @sprite mixin already contains width and height. If you need these values for something else, use the @sprite-width
and @sprite-height mixins.
### css task
```bash
gulp css --ext [extension name]
```
Triggers css compilation inside the given directory. Note, that this task will also run the sprite task before it starts.
Assumptions:
* all scss files are inside the sass directory, relative to the given path.
* all css files go into the stylesheets directory, relative to the given path.
### images task
```bash
gulp images --ext [extension name]
```
Optimizes all images for the given path.
Assumptions:
* all images are inside the image directory, relative to the given path.
### optimize images in fileadmin and uploads
```bash
gulp images:uploaded
```
This task optimizes all images (png, jpg, gif) inside the folders you specified in the config.json file. You might want to
run this task on a regular basis to compress user uploaded media.
# Troubleshooting
## Strange errors during npm install
If you get strange errors during npm install, it might help to clear the npm cache. To do so, run 'npm cache clean', oder simply delete the .npm directory inside your home folder.
\ No newline at end of file
'use strict';
var yeoman = require('yeoman-generator'),
chalk = require('chalk'),
yosay = require('yosay'),
path = require('path'),
_ = require('underscore'),
_s = require('underscore.string');
path = require('path');
module.exports = yeoman.generators.Base.extend((function() {
var Generator = {},
answers = {},
resourcePathsSuggestions = {
cssPath: path.join('Resources', 'Public', 'StyleSheets'),
sassPath: path.join('Resources', 'Public', 'Sass'),
imagesPath: path.join('Resources', 'Public', 'Images'),
javascriptPath: path.join('Resources', 'Public', 'Scripts'),
spritePath: 'Sprites',
svgPath: 'Svg'
};
module.exports = yeoman.Base.extend((function() {
var Generator = {};
Generator.initializing = function() {
Generator.pkg = require('../package.json');
......@@ -24,235 +14,80 @@ module.exports = yeoman.generators.Base.extend((function() {
Generator.prompting = {
basicPrompts: function() {
var done = this.async();
// Greet the user
this.log(yosay(
'Welcome to the dandy ' + chalk.red('Sgalinski') + ' generator!'
'Welcome to the ' + chalk.red('Sgalinski') + ' generator!'
));
this.log(chalk.bold.yellow('I will help you to setup a frontend build process for ' +
'your TYPO3 project with Extbase Extensions.\n\n'));
this.prompt([
{
type: 'input',
name: 'projectName',
message: 'Please enter the name of your project',
default: process.cwd().split(path.sep).pop()
}
], function(_answers) {
answers = _.extend(answers, _answers);
done();
});
},
pathPrompts: function() {
var done = this.async(),
questions;
// define questions
questions = [
{
type: 'input',
name: 'cssPath',
message: 'Please specify the path to the compiled css files',
default: resourcePathsSuggestions.cssPath
},
{
type: 'input',
name: 'sassPath',
message: 'Please specify the path to the sass source files',
default: resourcePathsSuggestions.sassPath
},
{
type: 'input',
name: 'javascriptPath',
message: 'Please specify the path to the javascript files',
default: resourcePathsSuggestions.javascriptPath
},
{
type: 'input',
name: 'imagesPath',
message: 'Please specify the path to the images',
default: resourcePathsSuggestions.imagesPath
},
{
type: 'input',
name: 'spritePath',
message: 'Please specify the path to the sprite images (relative to images)',
default: resourcePathsSuggestions.spritePath
},
{
type: 'input',
name: 'svgPath',
message: 'Please specify the path to the svg files (relative to images)',
default: resourcePathsSuggestions.svgPath
},
{
type: 'input',
name: 'extensions',
message: 'Please enter the names of the extensions you want gulp to watch for changes, ' +
'separated by commas (project_base, ext_one, ext_two).',
default: ''
}
];
// ask questions
this.prompt(questions, function(_answers) {
var extensionArray = _answers.extensions.split(',');
_answers.extensions = '';
for (var ext in extensionArray) {
if (extensionArray.hasOwnProperty(ext)) {
if (_answers.extensions !== '') {
_answers.extensions += ',\n\t\t';
}
_answers.extensions += '"' + _s.trim(extensionArray[ext]) + '"';
}
}
answers = _.extend(answers, _answers);
done();
});
},
cssPrompts: function() {
var done = this.async();
this.prompt([
{
type: 'input',
name: 'filesizeLimitCss',
message: 'Specify a maximum size (in Bytes) for CSS files. Leave blank if you don\'t want to ' +
'specify a limit',
default: ''
},
{
type: 'input',
name: 'filesizeLimitGzippedCss',
message: 'Specify a maximum size (in Bytes) for CSS files after gzip compression. Leave blank if you don\'t want to ' +
'specify a limit',
default: ''
}
], function(_answers) {
answers = _.extend(answers, _answers);
done();
});
},
javascriptPrompts: function() {
var done = this.async();
this.prompt([
{
type: 'input',
name: 'filesizeLimitJs',
message: 'Specify a maximum size (in Bytes) for JavaScript files. Leave blank if you don\'t want to ' +
'specify a limit',
default: ''
},
{
type: 'input',
name: 'filesizeLimitGzippedJs',
message: 'Specify a maximum size (in Bytes) for JavaScript files after gzip compression. Leave blank if you don\'t want to ' +
'specify a limit',
default: ''
}
], function(_answers) {
answers = _.extend(answers, _answers);
done();
});
},
configPrompts: function() {
var done = this.async();
this.prompt([
{
type: 'input',
name: 'autoprefixerBrowserSelection',
message: 'Please provide the configuration strings for autoprefixer',
default: '\'last 1 version\', \'> 1%\', \'ie 8\''
}
], function(_answers) {
answers = _.extend(answers, _answers);
done();
});
},
browserSyncPrompts: function() {
var done = this.async();
this.prompt({
type: 'input',
name: 'devUrl',
message: 'Please specify the URL where your TYPO3 site will be reachable during development',
default: answers.projectName + '.dev'
}, function(_answers) {
answers = _.extend(answers, _answers);
done();
});
}
};
Generator.writeGeneralConfigs = function() {
this.fs.copy(
this.templatePath('_editorconfig'),
this.templatePath('.editorconfig'),
this.destinationPath('.editorconfig')
);
this.fs.copy(
this.templatePath('_jshintrc'),
this.templatePath('.jshintrc'),
this.destinationPath('.jshintrc')
);
this.fs.copy(
this.templatePath('_scss-lint.yml'),
this.templatePath('.scss-lint.yml'),
this.destinationPath('.scss-lint.yml')
);
};
Generator.writeGulp = function() {
this.fs.copyTpl(
this.templatePath('_gulpfile.js'),
this.destinationPath('gulpfile.js'),
answers
this.fs.copy(
this.templatePath('gulpfile.js'),
this.destinationPath('gulpfile.js')
);
this.fs.copyTpl(
this.fs.copy(
this.templatePath('gulp/settings.js'),
this.destinationPath('gulp/settings.js'),
answers
this.destinationPath('gulp/settings.js')
);
this.fs.copyTpl(
this.fs.copy(
this.templatePath('gulp/css.js'),
this.destinationPath('gulp/css.js'),
answers
this.destinationPath('gulp/css.js')
);
this.fs.copyTpl(
this.templatePath('gulp/browser-sync.js'),
this.destinationPath('gulp/browser-sync.js'),
answers
this.fs.copy(
this.templatePath('gulp/browsersync.js'),
this.destinationPath('gulp/browsersync.js')
);
this.fs.copyTpl(
this.fs.copy(
this.templatePath('gulp/images.js'),
this.destinationPath('gulp/images.js'),
answers
this.destinationPath('gulp/images.js')
);
this.fs.copyTpl(
this.fs.copy(
this.templatePath('gulp/javascript.js'),
this.destinationPath('gulp/javascript.js'),
answers
this.destinationPath('gulp/javascript.js')
);
this.fs.copyTpl(
this.fs.copy(
this.templatePath('gulp/config.json'),
this.destinationPath('gulp/config.json'),
answers
this.destinationPath('gulp/config.json')
);
this.fs.copy(
this.templatePath('gulp/sprite-scss-template.mustache'),
this.destinationPath('gulp/sprite-scss-template.mustache'),
answers
this.destinationPath('gulp/sprite-scss-template.mustache')
);
this.fs.copy(
this.templatePath('gulp/inline-svg-template.mustache'),
this.destinationPath('gulp/inline-svg-template.mustache'),
answers
this.destinationPath('gulp/inline-svg-template.mustache')
);
this.fs.copy(
this.templatePath('install.sh'),
this.destinationPath('install.sh')
);
};
Generator.writeDependencyManagement = function() {
this.fs.copyTpl(
this.templatePath('_package.json'),
this.destinationPath('package.json'),
answers
this.fs.copy(
this.templatePath('package.json'),
this.destinationPath('package.json')
);
this.fs.copy(
this.templatePath('npm-shrinkwrap.json'),
this.destinationPath('npm-shrinkwrap.json')
);
};
...