- ×
A Yeoman generator for scaffolding an application using angular, browserify, ionic and famous
Filed under development aidsShow Allgenerator-mcfly
A Yeoman generator for scaffolding an application using angular, browserify or webpack, ionic, angular-ui-bootstrap, angular-material...
IMPORTANT UPDATE
The generator was previously named
generator-angular-famous-ionic
2 things to note:
installation is now
npm install -g generator-mcfly
If you have existing project modify the name of the generator in your
.yo-rc.json
file
Description
This generator will scaffold for you an application using angularjs, browserify or webpack, ionic framwork or angular-boostrap-ui or angular-material.
The project has the following capabilities:
- Angular best practices (feature folder structure)
- Sass AND Less enabled
- jshint, jscsc, eslint enabled (so you shouldn't have any typo left in your js files !)
- Webpack or Browserify (you can switch them out)
- Karma configured with Code Coverage
- Browser-sync
- TestFairy publishing
- Ionic.io publishing
It also supports ES6/7 by using the babel
NOTE:
This generator is using generator-sublime to scaffold common dot files (.jshintrc, .eslintrc, etc...).
Check it out https://www.npmjs.org/package/generator-sublimePrerequisites
In order to get the best experience with this generator, you have to install a couple of globals npm packages.
To do so you can execute, after the generator has runned, the following command:./bin/prepublish.sh
This will install, among others, the following packages globally:
- gulp
- browserify
- watchify
- webpack
- cordova
- ionic (cli) - A good cordova wrapper
Feel free to tweak
./bin/prepublish.sh
to add your own requirements.Usage
Install
generator-mcfly
:npm install -g generator-mcfly
Make a new directory, and
cd
into it:mkdir my-new-project && cd $_
Run
yo mcfly
, optionally passing an app name:yo mcfly [app-name]
Typical workflow
A typical workflow would look like this:
mkdir test-app && cd test-app yo mcfly yo mcfly:module common yo mcfly:controller common hello Add some content to client/index.html : <h2 ng-controller="main.common.hello as helloCtrl">{{helloCtrl.message}}</h2> gulp browsersync
NOTE:
gulp browsersync
accepts an option --no-browser if you do not want to automatically open a browserNOTE:
gulp browsersync
accepts an option --https if you do want to force an HTTPS connection
you can also control http vs https using ingulp_taks/common/constants.js
->serve.https
booleanUpgrade
I like to publish new versions as soon as possible. So here is the upgrade process.
npm update -g generator-mcfly
Client folder
The generator will ask you to provide the name of the folder containing the client source code, and it will save this value in
.yo-rc.json
file (clientFolder
entry).
If you rename the client folder, make sure you also modify the value stored in.yo-rc.json
Gulp tasks
Now that the project is created you have a set of simple gulp tasks command available
gulp help # List the main gulp tasks gulp lint # Run lint gulp test # Run lint, unit tests, and e2e tests gulp unit # Run lint and unit tests (karma for client + mocha for server) gulp karma # Run karma client unit tests gulp mocha # Run mocha server unit tests gulp e2e # Run protractor for end to end tests gulp browserify # Generate a distribution folder using browserify gulp webpack:run # Generate a distribution folder using webpack gulp style # Generate a main.css file gulp browsersync # Creates a browser-sync server, it will display its url, it watches for js / css / scss / html file changes and inject automatically the change in the browser gulp dist # Distribute the application gulp cordova:image # Generate the cordova icons and splashs gulp cordova:run # Run cordova run (accepts a --platform option)
The gulp tasks share a constant file located at
gulp/common/constants.js
. Feel free to modify it to your project needs.
The constants are resolved against the--target
option. The default value for--target
isapp
.To better understand the gulp task system have a look at the docs of gulp-mux
Ionic.io platform
The gulp system also includes some basic tasks for ensuring that your ionic projects in your
dist/
are able to make use of the apps.ionic.io platform. These are found ingulp_tasks/tasks/ionic.js
. To use the ionic.io platform services, you will need to scaffold a mobile target (withyo mcfly --mobile
oryo mcfly:target --mobile
) and then create a project on apps.ionic.io.Next make sure your target has the correct properties from your ionic project; most importantly the
app_id
,api_key
, andname
from apps.ionic.io. You should fill thes in inside yourgulp_tasks/common/constants.js
file, in theionic
section for your target. If you plan to useIonic Push
, make sure to also include thedev_push: true
property, so your app will know to register for the correct push notifications.If you don't see an entry in
constants.ionic
for your target, simply copy and fill in the one for theapp
target. Make sure you end up with aconstants.ionic
that looks like this:```js ionic: { ionicPlatform: { ... }, app: { ... }, <yourtargetname>: { // fill this object with your ionic.io details app_id: '123abcd', api_key: '0123456789abcdefghij0123456789abcdefghij012345', name: 'My New Ionic App', dev_push: true } } ```
After your save the constants you need, run
gulp ionic:platformcopy --target=<targetname>
to copy over the
ionic-platform-web-client
bundle into your client folder, injecting your project'sionic.io
data into it along the way.Next, uncomment the line that says
require('./ionic.io.bundle.min-<yourtargetname>');
atclient/scripts/main<targetsuffix>.js:14
as well as the module dependency for'ionic.service.core'
that follows it. Finally comment out the script include ofcordova.js
inclient/index<targetsuffix>.html:22
, since theionic.io.bundle.min.js
will automatically load the correct instance of thecordova.js
script for you.Currently
'ionic:deploy'
is the only entry-point task, and it runs a'dist'
and then handles the uploading and optional deployment of a project update to the ionic deploy server. You need to specify a target with a--target=<targetname>
and then which mode you're using (usuallyprod
) with--mode=<dev|prod>
. After that you can add the--note
and--deploy
flags as specified by theionic deploy
cli.More tasks to integrate with other ionic.io services are coming soon, but in the meantime, if you write your own, feel free to make a PR to
mcfly-io/generator-sublime
. The file to edit istemplates/gulps/tasks/ionic.js
. You should refer to the apps.ionic.io docs for inspiration, and then look ationic-app-lib
(the library that powersionic-cli
) to see how you can hook into the ionic system under the hood.Browserify/Webpack and namespaces
At the heart of the generator we use
browserify
orwebpack
to bundle together the client javascript files.
To switch betweenbrowserify
orwebpack
change the constant valuemoduleManager
ingulp_tasks/common/constants.js
('browserify'
or'webpack'
)Also because angular modules do not prevent name collision, each scaffolded component gets an unique full name composed like this:
[main app name].[module name].[component name]
Make sure you use that full name with DI.
Example:
If you need to require a module from another one, use the following code:Let's say you have scaffolded 2 modules with the generator,
common
andanalytics
. Sincecommon
is your base module you first need to connectanalytics
to it with arequire
. Do this in themodule.exports
inindex.js
forcommon
, right after therequire
forangular
. (Make sure you pass the namespace argument to therequire
.)var angular = require('angular'); var analytics = require('../analytics')(namespace);
Now that you have an
analytics
object that has been passed thenamespace
, you can dependency inject the module usinganalytics.name
. Create your app and inject the module.var app = angular.module(fullname, [..., analytics.name]);
Finally your app needs to not only have modules injected but also to be able to store the names of those modules in an easily accessible location. Attach a
namespace
object toapp
and give it ananalytics
property equal toanalytics.name
.app.namespace = app.namespace || {}; app.namespace.analytics = analytics.name;
You have now a reference between the 2 modules.
Note that the name of the modules are never hard coded :smile:We can very easily talk about the
analytics
module from any subcomponent inapp
, but beyond that, we can just as easily get the name of any of component ofanalytics
.Let's see how. Say that you've created a service on
analytics
calledmixpanelService
. You want to use that service in thehome
controller of thecommon
module.If you scaffolded
mixpanelService
using the generator you won't need to touch anything. If not go into your file and make sure that the name provided toapp.factory
looks likeapp.name + '.' + servicename
, which in this case evaluate asapp.name --> 'main.analytics' servicename --> 'mixpanel'
After being created, the service.name will look like
'main.analytics.mixpanel'
To inject
mixpanelService
intocommon
'shome
controller, go to/scripts/common/controllers/home.js
and dependency inject the service name appended to the pointer toanalytics.name
that you made before into yourdeps
array:var deps = [app.namespace.analytics + '.mixpanel']; function controller(mixpanel) { ... }
Again no hard coded namespace, and only one point of attachment between the modules :smile:
Generators
Available generators:
- mcfly (aka [mcfly:app] (#app))
- mcfly:target
- mcfly:module
- mcfly:controller
- mcfly:directive
- mcfly:filter
- mcfly:service
- mcfly:value
- mcfly:constant
- mcfly:require
Note: Generators are to be run from the root directory of your app.
App
Sets up a new AngularJS app, generating all the boilerplate you need to get started. The app generator also installs additional AngularJS modules, such as
- angular-mocks
- angular-animate
- angular-sanitize
- angular-ui-router
The main application is called
main
.Example:
yo mcfly
You can choose to scaffold a mobile (cordova) app using the option --mobile Example:
yo mcfly --mobile
This will scaffold a config.xml file (suffixed with the app name), and hooks expected by cordova.
In addition thedist
folder will conform to cordova expectation (www
sub folder).Target
Generate a new target application.
This is usefull if you want to share code between several applications (mobile, web, etc...).Example:
yo mcfly:target web
Produces:
client/index-web.html
client/scripts/main-web.js
client/styles/main-web.scss
NOTE:
By default the app generate a default application with no suffix. This is equivalent to running thetarget
generator with argumentapp
You can choose to scaffold a mobile (cordova) app using the option --mobile Example:
yo mcfly:target mymobileapp --mobile
This will scaffold a config.xml file (suffixed with the app name), and hooks expected by cordova.
In addition thedist
folder will conform to cordova expectation (www
sub folder).Module
Generates a new module. The first thing you need to do after executing
yo mcfly
is create a module.Example:
yo mcfly:module modulename
If you don't mention a modulename, yeoman will ask you to provide one.
Produces:
client/scripts/modulename/index.js
client/scripts/modulename/view/home.html
If you do not want any route for the module, you can use the option
--skip-route
Example:yo mcfly:module modulename --skip-route
In this case this will only produce:
client/scripts/modulename/index.js
Controller
Generates a new controller.
Example:
yo mcfly:controller modulename controllername
You need at least a module in order to scaffold a controller.
If you don't specify arguments, yeoman will display the list of existing modules and let you choose one.
Produces:
client/scripts/modulename/controllers/controllername.js
client/scripts/modulename/controllers/controllername.test.js
client/scripts/modulename/controllers/index.js
Filter
Generates a new filter.
Example:
yo mcfly:controller modulename filtername
You need at least a module in order to scaffold a filter.
If you don't specify arguments, yeoman will display the list of existing modules and let you choose one.Produces:
client/scripts/modulename/fiters/filtername.js
client/scripts/modulename/fiters/filtername.test.js
client/scripts/modulename/filters/index.js
Value
Generates a new value.
Example:
yo mcfly:value modulename valuename
You need at least a module in order to scaffold a value.
If you don't specify arguments, yeoman will display the list of existing modules and let you choose one.Produces:
client/scripts/modulename/values/valuename.js
client/scripts/modulename/values/valuename.test.js
client/scripts/modulename/values/index.js
Constant
Generates a new constant.
Example:
yo mcfly:value modulename constantname
You need at least a module in order to scaffold a constant.
If you don't specify arguments, yeoman will display the list of existing modules and let you choose one.Produces:
client/scripts/modulename/constants/constantname.js
client/scripts/modulename/constants/constantname.test.js
client/scripts/modulename/constants/index.js
Service
Generates a new service. You can use the
--servicetype
option to specify if you want a service, a factory, or a provider. Defaultservicetype
is factory.Example:
yo mcfly:service modulename servicename yo mcfly:service modulename servicename --servicetype=service yo mcfly:service modulename servicename --servicetype=provider
You need at least a module in order to scaffold a service.
If you don't specify arguments, yeoman will display the list of existing modules and let you choose one.Produces:
client/scripts/modulename/services/servicename.js
client/scripts/modulename/services/servicename.test.js
client/scripts/modulename/services/index.js
Directive
Generates a new directive. You can use the
--compile
option to specify if you want compile, pre and post link function (true), or just a simple link function (false). Defaultcompile
is true.Example:
yo mcfly:directive modulename myDirective yo mcfly:directive modulename myDirective --compile=false
You need at least a module in order to scaffold a directive.
If you don't specify arguments, yeoman will display the list of existing modules and let you choose one.Produces:
client/scripts/modulename/directives/myDirective.html
client/scripts/modulename/directives/myDirective.js
client/scripts/modulename/directives/myDirective.test.js
client/scripts/modulename/directives/index.js
Require
This generator will not scaffold any files.
Instead it inspects the existingclient
folder and will refresh the needed injected require statements in every file where it is relevant.Example:
yo mcfly:require
Adding a third party bower package
You should always prefer an npm package instead of a bower package. Most of client side libraries nowadays exist as both npm and bower packages. But sometimes it is not the case and you have to deal with a bower package.
If you want to include a third party bower package do the following:
bower install --save yourpackage
- modify
package.json
browser
section to include a path to the global minified javascript file of the package - adjust the font gulp constants (
gulp/common/constants.js
) to include the relevant fonts of the package (if applicable) - if the package exposes a global
.scss
file import it intoclient/styles/main.scss
and ajdust eventually the variable for the path font (should be../fonts
) - if the package only exposes a
.css
file adjust the css file constants (gulp/common/constants.js
) to include it - if the package relies on other libraries
- Either add a browser-shim section (but this will only work with browserify, not webpack)
- Or make sure you require the dependencies in your code just before you require the package.
Cordova applications
When you scaffold a mobile app (
yo mcfly:target myapp --mobile
), this will create acordova/myapp
folder underclient
.This folder contains hooks and resources (icons and spashs) that will be copied over during the
dist
gulp task.If you want to generate icons and splashes from a single icon file you can execute
gulp cordova:icon
It expects an
icon.png
file located in './client/icons/myapp` folder.The plugins you need for your mobile app must be added in the `./client/cordova/myapp/hooks/010_install_plugins.js' file.
The hook is responsible for installing them on relevant platforms.You first need to execute
gulp dist --t myapp
(with additional--mode
option i.edev
orprod
), in order to build the dist folder.Then you need to build the mobile platforms.
To do so run:cd dist/maypp/<dev or prod>/ cordova platform add <ios or android or ...>
When you run
gulp browsersync --target myapp
the task will detect thatmyapp
is a mobile app, and will automatically launch both a browser-sync browser window and a livereload emulator.
You can pass an addition--platform
option to tell it which emulator you want (ios, android, etc...).
If you don't pass--platform
it will choose the value fromconstants.js
(constants.cordova.platform
).When you are done with testing the app in the browser or the emulator, you can attach your phone device via an USB cable and run:
gulp cordova:run
If you want to upload your app to testfairy, first make sure you fill in your api_key for testfairy in
gulp_tasks/common/constants.js
,
and then simply rungulp cordova:testfairy
Cordova Content Security Policy
The
index.html
is configured to be permissive. Adjust the meta tagsContent-Security-Policy
to your needs. Reference is here : http://content-security-policy.com/Testing
To run unit test and e2e tests for the yeoman project use the following command:
gulp test
If you just want to run karma and are not interested yet in linting your files you can run:
gulp karma
If you wish to debug the code please use the --debug flag
gulp karma --debug
You can eventually also run karma in the background, with auto refresh using the option
--start
gulp karma --start
If you want to run karma with a specific bundle manager and a specific module, you can run:
gulp karma --bundler webpack --module common
If you just want to run mocha and are not interested yet in linting your files you can run:
gulp mocha
If you just want to run some specific unit test use:
mocha test/app.test.js -r test/helpers/globals.js
This will tell mocha to run only the tests located in
test/app.test.js
(The -r option is necessary here to add global configuration file for mocha, when using gulp theglobals.js
is added automatically)You can run e2e tests using the following command:
gulp e2e # the same as gulp e2e --coverage --target=app
This will dist and instrument the source code so you get code coverage, and use the default target
If you didn't change the source code you can bypass the dist:
gulp e2e --skip-dist
If you want another target:
gulp e2e --target=dashboard
Changelog
Recent changes can be viewed on Github on the Releases Page
License
BSD