151 | );
152 | }
153 | });
154 |
155 | return TodoApp;
156 |
157 | });
158 |
--------------------------------------------------------------------------------
/assets/js/TodoFooter.jsx:
--------------------------------------------------------------------------------
1 | define(['react', 'app/utils', 'classnames'], function (React, Utils, cx) {
2 | 'use strict';
3 |
4 | var TodoFooter = React.createClass({
5 | render: function () {
6 | var activeTodoWord = Utils.pluralize(this.props.count, 'item');
7 | var clearButton = null;
8 |
9 | if (this.props.completedCount > 0) {
10 | clearButton = (
11 |
16 | );
17 | }
18 |
19 | var nowShowing = this.props.nowShowing;
20 | return (
21 |
52 | );
53 | }
54 | });
55 |
56 | return TodoFooter;
57 |
58 | });
59 |
--------------------------------------------------------------------------------
/assets/js/TodoItem.jsx:
--------------------------------------------------------------------------------
1 | define(['react', 'classnames'], function (React, classNames) {
2 | 'use strict';
3 |
4 | var ESCAPE_KEY = 27;
5 | var ENTER_KEY = 13;
6 |
7 | var TodoItem = React.createClass({
8 | handleSubmit: function () {
9 | var val = this.state.editText.trim();
10 | if (val) {
11 | this.props.onSave(val);
12 | this.setState({editText: val});
13 | } else {
14 | this.props.onDestroy();
15 | }
16 | return false;
17 | },
18 |
19 | handleEdit: function () {
20 | // react optimizes renders by batching them. This means you can't call
21 | // parent's `onEdit` (which in this case triggeres a re-render), and
22 | // immediately manipulate the DOM as if the rendering's over. Put it as a
23 | // callback. Refer to app.js' `edit` method
24 | this.props.onEdit(function () {
25 | var node = this.refs.editField.findDOMNode();
26 | node.focus();
27 | node.setSelectionRange(node.value.length, node.value.length);
28 | }.bind(this));
29 | this.setState({editText: this.props.todo.title});
30 | },
31 |
32 | handleKeyDown: function (event) {
33 | if (event.which === ESCAPE_KEY) {
34 | this.setState({editText: this.props.todo.title});
35 | this.props.onCancel();
36 | } else if (event.which === ENTER_KEY) {
37 | this.handleSubmit();
38 | }
39 | },
40 |
41 | handleChange: function (event) {
42 | this.setState({editText: event.target.value});
43 | },
44 |
45 | getInitialState: function () {
46 | return {editText: this.props.todo.title};
47 | },
48 |
49 | /**
50 | * This is a completely optional performance enhancement that you can implement
51 | * on any React component. If you were to delete this method the app would still
52 | * work correctly (and still be very performant!), we just use it as an example
53 | * of how little code it takes to get an order of magnitude performance improvement.
54 | */
55 | shouldComponentUpdate: function (nextProps, nextState) {
56 | return (
57 | nextProps.todo !== this.props.todo ||
58 | nextProps.editing !== this.props.editing ||
59 | nextState.editText !== this.state.editText
60 | );
61 | },
62 |
63 | render: function () {
64 | return (
65 |
69 |
70 |
76 |
79 |
80 |
81 |
89 |
90 | );
91 | }
92 | });
93 |
94 | return TodoItem;
95 |
96 | });
97 |
--------------------------------------------------------------------------------
/assets/js/TodoModel.js:
--------------------------------------------------------------------------------
1 | define(['app/utils'], function (Utils) {
2 | 'use strict';
3 |
4 | // Generic "model" object. You can use whatever
5 | // framework you want. For this application it
6 | // may not even be worth separating this logic
7 | // out, but we do this to demonstrate one way to
8 | // separate out parts of your application.
9 | var TodoModel = function (url, socket) {
10 | this.url = url;
11 | this.socket = socket;
12 | this.onChanges = [];
13 | this.todos = [];
14 | };
15 |
16 | TodoModel.prototype.set = function(data) {
17 | this.todos = data;
18 | this.inform();
19 | };
20 |
21 | TodoModel.prototype.subscribe = function (onChange) {
22 | this.onChanges.push(onChange);
23 | };
24 |
25 | TodoModel.prototype.inform = function () {
26 | this.onChanges.forEach(function (cb) { cb(); });
27 | };
28 |
29 | TodoModel.prototype.addTodo = function (title) {
30 | var todo = {
31 | uid: Utils.uuid(), //not used anymore
32 | title: title,
33 | completed: false
34 | };
35 |
36 | this.socket.post(this.url, todo, function whenServerResponds(data) {
37 | this.todos = this.todos.concat(data);
38 | console.log('Message posted :: ', data);
39 | }.bind(this));
40 |
41 | };
42 |
43 | TodoModel.prototype.toggleAll = function (checked) {
44 | this.todos.forEach(function (todo) {
45 | this.socket.put(this.url + '/' + todo.id, {completed: checked}, function whenServerResponds(data) {
46 | console.log('Message toggleAll :: ', data);
47 | });
48 | }.bind(this));
49 | };
50 |
51 | TodoModel.prototype.toggle = function (todoToToggle) {
52 | this.socket.put(this.url + '/' + todoToToggle.id, {completed: !todoToToggle.completed}, function whenServerResponds(data) {
53 | console.log('Message toggle :: ', data);
54 | });
55 | };
56 |
57 | TodoModel.prototype.destroy = function (todo) {
58 | this.socket.delete(this.url + '/' + todo.id, function whenServerResponds(data) {
59 | console.log('Message destroy :: ', data);
60 | });
61 | };
62 |
63 | TodoModel.prototype.save = function (todoToSave, text) {
64 | this.socket.put(this.url + '/' + todoToSave.id, {title: text}, function whenServerResponds(data) {
65 | console.log('Message save :: ', data);
66 | });
67 | };
68 |
69 | TodoModel.prototype.clearCompleted = function () {
70 | this.todos.forEach(function (todo) {
71 | if(todo.completed)
72 | this.socket.delete(this.url + '/' + todo.id, function whenServerResponds(data) {
73 | console.log('Message destroy :: ', data);
74 | });
75 | }.bind(this));
76 | };
77 |
78 | return TodoModel;
79 |
80 | });
81 |
--------------------------------------------------------------------------------
/assets/js/commentMain.jsx:
--------------------------------------------------------------------------------
1 | requirejs.config({
2 | paths: {
3 | 'react': '/bower_components/react/react-with-addons',
4 | 'reactdom': '/bower_components/react/react-dom',
5 | 'jquery': '/bower_components/jquery/dist/jquery',
6 | 'jquery.timeago': '/bower_components/jquery-timeago/jquery.timeago',
7 | 'showdown': '/bower_components/showdown/compressed/Showdown',
8 | 'bootstrap': '/bower_components/bootstrap/dist/js/bootstrap',
9 | 'app': '/js'
10 | },
11 |
12 | shim: {
13 | 'jquery.timeago': ["jquery"]
14 | }
15 | });
16 |
17 | require(['jquery', 'react', 'reactdom', 'app/CommentForm', 'app/CommentList'],
18 | function ($, React, ReactDOM, CommentForm, CommentList) {
19 |
20 |
21 | $(function whenDomIsReady() {
22 |
23 | ReactDOM.render(
24 | ,
25 | document.getElementById('commentForm')
26 | );
27 |
28 | // as soon as this file is loaded, connect automatically,
29 | var socket = io.sails.connect();
30 |
31 | console.log('Connecting to Sails.js...');
32 |
33 | // Subscribe to updates (a sails get or post will auto subscribe to updates)
34 | socket.get('/comment', function (message) {
35 | console.log('Listening...' + message);
36 |
37 | // initialize the view with the data property
38 | ReactDOM.render(
39 | ,
40 | document.getElementById('commentList')
41 | );
42 |
43 | });
44 |
45 | // Expose connected `socket` instance globally so that it's easy
46 | // to experiment with from the browser console while prototyping.
47 | window.socket = socket;
48 |
49 | });
50 |
51 |
52 | });
--------------------------------------------------------------------------------
/assets/js/todoMain.jsx:
--------------------------------------------------------------------------------
1 | requirejs.config({
2 | paths: {
3 | 'react': '/bower_components/react/react-with-addons',
4 | 'reactdom': '/bower_components/react/react-dom',
5 | 'classnames': '/bower_components/classnames/index',
6 | 'app': '/js'
7 | },
8 | });
9 |
10 | require(['react', 'reactdom', 'app/TodoModel', 'app/TodoApp'],
11 | function (React, ReactDOM, TodoModel, TodoApp) {
12 |
13 | // as soon as this file is loaded, connect automatically,
14 | var socket = io.sails.connect();
15 |
16 | var model = new TodoModel('/todo', socket);
17 |
18 | function render() {
19 |
20 | ReactDOM.render(
21 | ,
22 | document.getElementById('todoapp')
23 | );
24 | }
25 |
26 |
27 | console.log('Connecting to Sails.js...');
28 |
29 | // Subscribe to updates (a sails get or post will auto subscribe to updates)
30 | socket.get('/todo', function (message) {
31 |
32 | console.log('Listening...' + JSON.stringify(message));
33 |
34 | // initialize the view with the data property
35 | model.set(message);
36 | model.subscribe(render);
37 | render();
38 |
39 | });
40 |
41 | socket.on('todo', function whenMessageRecevied(message) {
42 | console.log('New comet message received :: ', message);
43 |
44 | // TODO brute force it. should really check the type of message and respond accordingly.
45 | // for now we just update the whole list (this requires the mirror option in config/blueprint)
46 | socket.get('/todo', function (todos) {
47 | model.set(todos);
48 | });
49 |
50 | });
51 |
52 |
53 | }); //require
--------------------------------------------------------------------------------
/assets/js/utils.js:
--------------------------------------------------------------------------------
1 | define([], function () {
2 | 'use strict';
3 |
4 | var utils = {
5 | uuid: function () {
6 | /*jshint bitwise:false */
7 | var i, random;
8 | var uuid = '';
9 |
10 | for (i = 0; i < 32; i++) {
11 | random = Math.random() * 16 | 0;
12 | if (i === 8 || i === 12 || i === 16 || i === 20) {
13 | uuid += '-';
14 | }
15 | uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random))
16 | .toString(16);
17 | }
18 |
19 | return uuid;
20 | },
21 |
22 | pluralize: function (count, word) {
23 | return count === 1 ? word : word + 's';
24 | },
25 |
26 | ALL_TODOS: 'all',
27 |
28 | ACTIVE_TODOS: 'active',
29 |
30 | COMPLETED_TODOS: 'completed'
31 | };
32 |
33 |
34 | return utils;
35 |
36 | });
--------------------------------------------------------------------------------
/assets/robots.txt:
--------------------------------------------------------------------------------
1 | # The robots.txt file is used to control how search engines index your live URLs.
2 | # See http://www.robotstxt.org/wc/norobots.html for more information.
3 |
4 |
5 |
6 | # To prevent search engines from seeing the site altogether, uncomment the next two lines:
7 | # User-Agent: *
8 | # Disallow: /
9 |
--------------------------------------------------------------------------------
/assets/styles/importer.less:
--------------------------------------------------------------------------------
1 | /**
2 | * importer.less
3 | *
4 | * By default, new Sails projects are configured to compile this file
5 | * from LESS to CSS. Unlike CSS files, LESS files are not compiled and
6 | * included automatically unless they are imported below.
7 | *
8 | * The LESS files imported below are compiled and included in the order
9 | * they are listed. Mixins, variables, etc. should be imported first
10 | * so that they can be accessed by subsequent LESS stylesheets.
11 | *
12 | * (Just like the rest of the asset pipeline bundled in Sails, you can
13 | * always omit, customize, or replace this behavior with SASS, SCSS,
14 | * or any other Grunt tasks you like.)
15 | */
16 |
17 |
18 |
19 | // For example:
20 | //
21 | // @import 'variables/colors.less';
22 | // @import 'mixins/foo.less';
23 | // @import 'mixins/bar.less';
24 | // @import 'mixins/baz.less';
25 | //
26 | // @import 'styleguide.less';
27 | // @import 'pages/login.less';
28 | // @import 'pages/signup.less';
29 | //
30 | // etc.
31 |
--------------------------------------------------------------------------------
/assets/styles/styles.css:
--------------------------------------------------------------------------------
1 | .example-enter {
2 | opacity: 0.01;
3 | transition: opacity .5s ease-in;
4 | }
5 |
6 | .example-enter.example-enter-active {
7 | opacity: 1;
8 | }
9 |
10 | .example-leave {
11 | opacity: 1;
12 | transition: opacity .5s ease-in;
13 | }
14 |
15 | .example-leave.example-leave-active {
16 | opacity: 0.01;
17 | }
--------------------------------------------------------------------------------
/assets/templates/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mixxen/sails-react-example/d9259d7bd84fd41e78eb66b6ce8f6e4d54204e08/assets/templates/.gitkeep
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sails-react-example",
3 | "version": "0.3.0",
4 | "homepage": "https://github.com/mixxen/sails-react-example",
5 | "authors": [
6 | "alexander.cabello@gmail.com "
7 | ],
8 | "moduleType": [
9 | "amd"
10 | ],
11 | "license": "MIT",
12 | "ignore": [
13 | "**/.*",
14 | "node_modules",
15 | "bower_components",
16 | "assets/bower_components",
17 | "test",
18 | "tests"
19 | ],
20 | "dependencies": {
21 | "react": "~0.14.7",
22 | "jquery": "~2.2.0",
23 | "bootstrap": "~3.3.6",
24 | "jquery-timeago": "~1.4.1",
25 | "requirejs": "~2.1.22",
26 | "showdown": "~0.3.1",
27 | "todomvc-common": "~0.1.9",
28 | "director": "~1.2.2",
29 | "classnames": "~2.2.3"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/config/blueprints.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Blueprint API Configuration
3 | * (sails.config.blueprints)
4 | *
5 | * These settings are for the global configuration of blueprint routes and
6 | * request options (which impact the behavior of blueprint actions).
7 | *
8 | * You may also override any of these settings on a per-controller basis
9 | * by defining a '_config' key in your controller defintion, and assigning it
10 | * a configuration object with overrides for the settings in this file.
11 | *
12 | * For more information on configuring the blueprint API, check out:
13 | * http://links.sailsjs.org/docs/config/blueprints
14 | */
15 |
16 | module.exports.blueprints = {
17 |
18 |
19 | /**
20 | * NOTE:
21 | * A lot of the configuration options below affect so-called "CRUD methods",
22 | * or your controllers' `find`, `create`, `update`, and `destroy` actions.
23 | *
24 | * It's important to realize that, even if you haven't defined these yourself, as long as
25 | * a model exists with the same name as the controller, Sails will respond with built-in CRUD
26 | * logic in the form of a JSON API, including support for sort, pagination, and filtering.
27 | */
28 |
29 |
30 |
31 | // Action blueprints speed up the backend development workflow by eliminating the need
32 | // to manually bind routes. When enabled, GET, POST, PUT, and DELETE routes will be
33 | // generated for every one of a controller's actions.
34 | //
35 | // If an `index` action exists, additional naked routes will be created for it.
36 | // Finally, all `actions` blueprints support an optional path parameter, `id`, for convenience.
37 | //
38 | // For example, assume we have an EmailController with actions `send` and `index`.
39 | // With `actions` enabled, the following blueprint routes would be bound at runtime:
40 | //
41 | // `EmailController.index`
42 | // :::::::::::::::::::::::::::::::::::::::::::::::::::::::
43 | // `GET /email/:id?` `GET /email/index/:id?`
44 | // `POST /email/:id?` `POST /email/index/:id?`
45 | // `PUT /email/:id?` `PUT /email/index/:id?`
46 | // `DELETE /email/:id?` `DELETE /email/index/:id?`
47 | //
48 | // `EmailController.send`
49 | // :::::::::::::::::::::::::::::::::::::::::::::::::::::::
50 | // `GET /email/send/:id?`
51 | // `POST /email/send/:id?`
52 | // `PUT /email/send/:id?`
53 | // `DELETE /email/send/:id?`
54 | //
55 | //
56 | // `actions` are enabled by default, and can be OK for production-- however,
57 | // if you'd like to continue to use controller/action autorouting in a production deployment,
58 | // you must take great care not to inadvertently expose unsafe/unintentional controller logic
59 | // to GET requests.
60 | actions: true,
61 |
62 |
63 |
64 | // RESTful Blueprints
65 | // (`sails.config.blueprints.rest`)
66 | //
67 | // REST blueprints are the automatically generated routes Sails uses to expose
68 | // a conventional REST API on top of a controller's `find`, `create`, `update`, and `destroy`
69 | // actions.
70 | //
71 | // For example, a BoatController with `rest` enabled generates the following routes:
72 | // :::::::::::::::::::::::::::::::::::::::::::::::::::::::
73 | // GET /boat/:id? -> BoatController.find
74 | // POST /boat -> BoatController.create
75 | // PUT /boat/:id -> BoatController.update
76 | // DELETE /boat/:id -> BoatController.destroy
77 | //
78 | // `rest` blueprint routes are enabled by default, and are suitable for use
79 | // in a production scenario, as long you take standard security precautions
80 | // (combine w/ policies, etc.)
81 | rest: true,
82 |
83 |
84 | // Shortcut blueprints are simple helpers to provide access to a controller's CRUD methods
85 | // from your browser's URL bar. When enabled, GET, POST, PUT, and DELETE routes will be generated
86 | // for the controller's`find`, `create`, `update`, and `destroy` actions.
87 | //
88 | // `shortcuts` are enabled by default, but should be disabled in production.
89 | shortcuts: true,
90 |
91 |
92 |
93 | // An optional mount path for all blueprint routes on a controller, including `rest`,
94 | // `actions`, and `shortcuts`. This allows you to take advantage of blueprint routing,
95 | // even if you need to namespace your API methods.
96 | //
97 | // * (NOTE: This only applies to blueprint autoroutes, not manual routes from `sails.config.routes`)
98 | //
99 | // For example, `prefix: '/api/v2'` would make the following REST blueprint routes
100 | // for a FooController:
101 | //
102 | // `GET /api/v2/foo/:id?`
103 | // `POST /api/v2/foo`
104 | // `PUT /api/v2/foo/:id`
105 | // `DELETE /api/v2/foo/:id`
106 | //
107 | // By default, no prefix is used.
108 | prefix: '',
109 |
110 |
111 |
112 | // Whether to pluralize controller names in blueprint routes.
113 | //
114 | // (NOTE: This only applies to blueprint autoroutes, not manual routes from `sails.config.routes`)
115 | //
116 | // For example, REST blueprints for `FooController` with `pluralize` enabled:
117 | // GET /foos/:id?
118 | // POST /foos
119 | // PUT /foos/:id?
120 | // DELETE /foos/:id?
121 | pluralize: false,
122 |
123 | // TODO this is not a good idea for production
124 | mirror: true
125 |
126 | };
127 |
--------------------------------------------------------------------------------
/config/bootstrap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Bootstrap
3 | * (sails.config.bootstrap)
4 | *
5 | * An asynchronous bootstrap function that runs before your Sails app gets lifted.
6 | * This gives you an opportunity to set up your data model, run jobs, or perform some special logic.
7 | *
8 | * For more information on bootstrapping your app, check out:
9 | * http://links.sailsjs.org/docs/config/bootstrap
10 | */
11 |
12 | module.exports.bootstrap = function(cb) {
13 |
14 | // It's very important to trigger this callack method when you are finished
15 | // with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap)
16 | cb();
17 | };
18 |
--------------------------------------------------------------------------------
/config/connections.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Connections
3 | * (sails.config.connections)
4 | *
5 | * `Connections` are like "saved settings" for your adapters. What's the difference between
6 | * a connection and an adapter, you might ask? An adapter (e.g. `sails-mysql`) is generic--
7 | * it needs some additional information to work (e.g. your database host, password, user, etc.)
8 | * A `connection` is that additional information.
9 | *
10 | * Each model must have a `connection` property (a string) which is references the name of one
11 | * of these connections. If it doesn't, the default `connection` configured in `config/models.js`
12 | * will be applied. Of course, a connection can (and usually is) shared by multiple models.
13 | * .
14 | * Note: If you're using version control, you should put your passwords/api keys
15 | * in `config/local.js`, environment variables, or use another strategy.
16 | * (this is to prevent you inadvertently sensitive credentials up to your repository.)
17 | *
18 | * For more information on configuration, check out:
19 | * http://links.sailsjs.org/docs/config/connections
20 | */
21 |
22 | module.exports.connections = {
23 |
24 | // Local disk storage for DEVELOPMENT ONLY
25 | //
26 | // Installed by default.
27 | //
28 | localDiskDb: {
29 | adapter: 'sails-disk'
30 | },
31 |
32 | // MySQL is the world's most popular relational database.
33 | // http://en.wikipedia.org/wiki/MySQL
34 | //
35 | // Run:
36 | // npm install sails-mysql
37 | //
38 | someMysqlServer: {
39 | adapter: 'sails-mysql',
40 | host: 'YOUR_MYSQL_SERVER_HOSTNAME_OR_IP_ADDRESS',
41 | user: 'YOUR_MYSQL_USER',
42 | password: 'YOUR_MYSQL_PASSWORD',
43 | database: 'YOUR_MYSQL_DB'
44 | },
45 |
46 | // MongoDB is the leading NoSQL database.
47 | // http://en.wikipedia.org/wiki/MongoDB
48 | //
49 | // Run:
50 | // npm install sails-mongo
51 | //
52 | someMongodbServer: {
53 | adapter: 'sails-mongo',
54 | host: 'localhost',
55 | port: 27017,
56 | // user: 'username',
57 | // password: 'password',
58 | // database: 'your_mongo_db_name_here'
59 | },
60 |
61 | // PostgreSQL is another officially supported relational database.
62 | // http://en.wikipedia.org/wiki/PostgreSQL
63 | //
64 | // Run:
65 | // npm install sails-postgresql
66 | //
67 | somePostgresqlServer: {
68 | adapter: 'sails-postgresql',
69 | host: 'YOUR_POSTGRES_SERVER_HOSTNAME_OR_IP_ADDRESS',
70 | user: 'YOUR_POSTGRES_USER',
71 | password: 'YOUR_POSTGRES_PASSWORD',
72 | database: 'YOUR_POSTGRES_DB'
73 | }
74 |
75 |
76 | // More adapters:
77 | // https://github.com/balderdashy/sails
78 |
79 | };
80 |
--------------------------------------------------------------------------------
/config/cors.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Cross-Origin Resource Sharing (CORS) Settings
3 | * (sails.config.cors)
4 | *
5 | * CORS is like a more modern version of JSONP-- it allows your server/API
6 | * to successfully respond to requests from client-side JavaScript code
7 | * running on some other domain (e.g. google.com)
8 | * Unlike JSONP, it works with POST, PUT, and DELETE requests
9 | *
10 | * For more information on CORS, check out:
11 | * http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
12 | *
13 | * Note that any of these settings (besides 'allRoutes') can be changed on a per-route basis
14 | * by adding a "cors" object to the route configuration:
15 | *
16 | * '/get foo': {
17 | * controller: 'foo',
18 | * action: 'bar',
19 | * cors: {
20 | * origin: 'http://foobar.com,https://owlhoot.com'
21 | * }
22 | * }
23 | *
24 | */
25 |
26 | module.exports.cors = {
27 |
28 | // Allow CORS on all routes by default? If not, you must enable CORS on a
29 | // per-route basis by either adding a "cors" configuration object
30 | // to the route config, or setting "cors:true" in the route config to
31 | // use the default settings below.
32 | allRoutes: false,
33 |
34 | // Which domains which are allowed CORS access?
35 | // This can be a comma-delimited list of hosts (beginning with http:// or https://)
36 | // or "*" to allow all domains CORS access.
37 | origin: '*',
38 |
39 | // Allow cookies to be shared for CORS requests?
40 | credentials: true,
41 |
42 | // Which methods should be allowed for CORS requests? This is only used
43 | // in response to preflight requests (see article linked above for more info)
44 | methods: 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
45 |
46 | // Which headers should be allowed for CORS requests? This is only used
47 | // in response to preflight requests.
48 | headers: 'content-type'
49 |
50 | };
51 |
--------------------------------------------------------------------------------
/config/csrf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Cross-Site Request Forgery Protection Settings
3 | * (sails.config.csrf)
4 | *
5 | * CSRF tokens are like a tracking chip. While a session tells the server that a user
6 | * "is who they say they are", a csrf token tells the server "you are where you say you are".
7 | *
8 | * When enabled, all non-GET requests to the Sails server must be accompanied by
9 | * a special token, identified as the '_csrf' parameter.
10 | *
11 | * This option protects your Sails app against cross-site request forgery (or CSRF) attacks.
12 | * A would-be attacker needs not only a user's session cookie, but also this timestamped,
13 | * secret CSRF token, which is refreshed/granted when the user visits a URL on your app's domain.
14 | *
15 | * This allows us to have certainty that our users' requests haven't been hijacked,
16 | * and that the requests they're making are intentional and legitimate.
17 | *
18 | * This token has a short-lived expiration timeline, and must be acquired by either:
19 | *
20 | * (a) For traditional view-driven web apps:
21 | * Fetching it from one of your views, where it may be accessed as
22 | * a local variable, e.g.:
23 | *
26 | *
27 | * or (b) For AJAX/Socket-heavy and/or single-page apps:
28 | * Sending a GET request to the `/csrfToken` route, where it will be returned
29 | * as JSON, e.g.:
30 | * { _csrf: 'ajg4JD(JGdajhLJALHDa' }
31 | *
32 | *
33 | * Enabling this option requires managing the token in your front-end app.
34 | * For traditional web apps, it's as easy as passing the data from a view into a form action.
35 | * In AJAX/Socket-heavy apps, just send a GET request to the /csrfToken route to get a valid token.
36 | *
37 | * For more information on CSRF, check out:
38 | * http://en.wikipedia.org/wiki/Cross-site_request_forgery
39 | */
40 |
41 | module.exports.csrf = false;
42 |
--------------------------------------------------------------------------------
/config/globals.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Global Variable Configuration
3 | * (sails.config.globals)
4 | *
5 | * Configure which global variables which will be exposed
6 | * automatically by Sails.
7 | *
8 | * For more information on configuration, check out:
9 | * http://links.sailsjs.org/docs/config/globals
10 | */
11 | module.exports.globals = {
12 | _: true,
13 | async: true,
14 | sails: true,
15 | services: true,
16 | models: true
17 | };
18 |
--------------------------------------------------------------------------------
/config/http.js:
--------------------------------------------------------------------------------
1 | /**
2 | * HTTP Server Settings
3 | * (sails.config.http)
4 | *
5 | * Configuration for the underlying HTTP server in Sails.
6 | * Only applies to HTTP requests (not WebSockets)
7 | *
8 | * For more information on configuration, check out:
9 | * http://links.sailsjs.org/docs/config/http
10 | */
11 |
12 | module.exports.http = {
13 |
14 | middleware: {
15 |
16 | // The order in which middleware should be run for HTTP request.
17 | // (the Sails router is invoked by the "router" middleware below.)
18 | order: [
19 | 'startRequestTimer',
20 | 'cookieParser',
21 | 'session',
22 | 'bodyParser',
23 | 'handleBodyParserError',
24 | 'compress',
25 | 'methodOverride',
26 | 'poweredBy',
27 | '$custom',
28 | 'router',
29 | 'www',
30 | 'favicon',
31 | '404',
32 | '500'
33 | ],
34 |
35 | // The body parser that will handle incoming multipart HTTP requests.
36 | // By default as of v0.10, Sails uses [skipper](http://github.com/balderdashy/skipper).
37 | // See http://www.senchalabs.org/connect/multipart.html for other options.
38 | // bodyParser: require('skipper')
39 |
40 | },
41 |
42 | // The number of seconds to cache flat files on disk being served by
43 | // Express static middleware (by default, these files are in `.tmp/public`)
44 | //
45 | // The HTTP static cache is only active in a 'production' environment,
46 | // since that's the only time Express will cache flat-files.
47 | cache: 31557600000
48 | };
49 |
--------------------------------------------------------------------------------
/config/i18n.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Internationalization / Localization Settings
3 | * (sails.config.i18n)
4 | *
5 | * If your app will touch people from all over the world, i18n (or internationalization)
6 | * may be an important part of your international strategy.
7 | *
8 | *
9 | * For more information, check out:
10 | * http://links.sailsjs.org/docs/config/i18n
11 | */
12 |
13 | module.exports.i18n = {
14 |
15 | // Which locales are supported?
16 | locales: ['en', 'es', 'fr', 'de']
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/config/locales/_README.md:
--------------------------------------------------------------------------------
1 | # Internationalization / Localization Settings
2 |
3 | > Also see the official docs on internationalization/localization:
4 | > http://links.sailsjs.org/docs/config/locales
5 |
6 | ## Locales
7 | All locale files live under `config/locales`. Here is where you can add translations
8 | as JSON key-value pairs. The name of the file should match the language that you are supporting, which allows for automatic language detection based on request headers.
9 |
10 | Here is an example locale stringfile for the Spanish language (`config/locales/es.json`):
11 | ```json
12 | {
13 | "Hello!": "Hola!",
14 | "Hello %s, how are you today?": "¿Hola %s, como estas?",
15 | }
16 | ```
17 | ## Usage
18 | Locales can be accessed in controllers/policies through `res.i18n()`, or in views through the `__(key)` or `i18n(key)` functions.
19 | Remember that the keys are case sensitive and require exact key matches, e.g.
20 |
21 | ```ejs
22 |
<%= __('Welcome to PencilPals!') %>
23 |
<%= i18n('Hello %s, how are you today?', 'Pencil Maven') %>
24 |
<%= i18n('That\'s right-- you can use either i18n() or __()') %>
25 | ```
26 |
27 | ## Configuration
28 | Localization/internationalization config can be found in `config/i18n.js`, from where you can set your supported locales.
29 |
--------------------------------------------------------------------------------
/config/locales/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Wilkommen"
3 | }
--------------------------------------------------------------------------------
/config/locales/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Welcome"
3 | }
4 |
--------------------------------------------------------------------------------
/config/locales/es.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Bienvenido"
3 | }
4 |
--------------------------------------------------------------------------------
/config/locales/fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "Welcome": "Bienvenue"
3 | }
4 |
--------------------------------------------------------------------------------
/config/log.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Built-in Log Configuration
3 | * (sails.config.log)
4 | *
5 | * Configure the log level for your app, as well as the transport
6 | * (Underneath the covers, Sails uses Winston for logging, which
7 | * allows for some pretty neat custom transports/adapters for log messages)
8 | *
9 | * For more information on the Sails logger, check out:
10 | * http://links.sailsjs.org/docs/config/log
11 | */
12 |
13 | module.exports = {
14 |
15 | // Valid `level` configs:
16 | // i.e. the minimum log level to capture with sails.log.*()
17 | //
18 | // 'error' : Display calls to `.error()`
19 | // 'warn' : Display calls from `.error()` to `.warn()`
20 | // 'debug' : Display calls from `.error()`, `.warn()` to `.debug()`
21 | // 'info' : Display calls from `.error()`, `.warn()`, `.debug()` to `.info()`
22 | // 'verbose': Display calls from `.error()`, `.warn()`, `.debug()`, `.info()` to `.verbose()`
23 | //
24 | log: {
25 | level: 'info'
26 | }
27 |
28 | };
29 |
--------------------------------------------------------------------------------
/config/models.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Default model configuration
3 | * (sails.config.models)
4 | *
5 | * Unless you override them, the following properties will be included
6 | * in each of your models.
7 | */
8 |
9 | module.exports.models = {
10 |
11 | // Your app's default connection.
12 | // i.e. the name of one of your app's connections (see `config/connections.js`)
13 | //
14 | // (defaults to localDiskDb)
15 | connection: 'localDiskDb',
16 | migrate: 'safe'
17 | };
18 |
--------------------------------------------------------------------------------
/config/policies.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Policy Mappings
3 | * (sails.config.policies)
4 | *
5 | * Policies are simple functions which run **before** your controllers.
6 | * You can apply one or more policies to a given controller, or protect
7 | * its actions individually.
8 | *
9 | * Any policy file (e.g. `api/policies/authenticated.js`) can be accessed
10 | * below by its filename, minus the extension, (e.g. "authenticated")
11 | *
12 | * For more information on configuring policies, check out:
13 | * http://sailsjs.org/#!documentation/
14 | */
15 |
16 |
17 | module.exports.policies = {
18 |
19 | // Default policy for all controllers and actions
20 | // (`true` allows public access)
21 | '*': true,
22 |
23 | // Here's an example of mapping some policies to run before
24 | // a controller and its actions
25 | // RabbitController: {
26 |
27 | // Apply the `false` policy as the default for all of RabbitController's actions
28 | // (`false` prevents all access, which ensures that nothing bad happens to our rabbits)
29 | // '*': false,
30 |
31 | // For the action `nurture`, apply the 'isRabbitMother' policy
32 | // (this overrides `false` above)
33 | // nurture : 'isRabbitMother',
34 |
35 | // Apply the `isNiceToAnimals` AND `hasRabbitFood` policies
36 | // before letting any users feed our rabbits
37 | // feed : ['isNiceToAnimals', 'hasRabbitFood']
38 | // }
39 | };
40 |
--------------------------------------------------------------------------------
/config/routes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Route Mappings
3 | * (sails.config.routes)
4 | *
5 | * Your routes map URLs to views and controllers.
6 | *
7 | * If Sails receives a URL that doesn't match any of the routes below,
8 | * it will check for matching files (images, scripts, stylesheets, etc.)
9 | * in your assets directory. e.g. `http://localhost:1337/images/foo.jpg`
10 | * might match an image file: `/assets/images/foo.jpg`
11 | *
12 | * Finally, if those don't match either, the default 404 handler is triggered.
13 | * See `config/404.js` to adjust your app's 404 logic.
14 | *
15 | * Note: Sails doesn't ACTUALLY serve stuff from `assets`-- the default Gruntfile in Sails copies
16 | * flat files from `assets` to `.tmp/public`. This allows you to do things like compile LESS or
17 | * CoffeeScript for the front-end.
18 | *
19 | * For more information on routes, check out:
20 | * http://links.sailsjs.org/docs/config/routes
21 | */
22 |
23 | module.exports.routes = {
24 |
25 |
26 | // Make the view located at `views/homepage.ejs` (or `views/homepage.jade`, etc. depending on your
27 | // default view engine) your home page.
28 | //
29 | // (Alternatively, remove this and add an `index.html` file in your `assets` directory)
30 | '/': {
31 | view: 'homepage'
32 | },
33 |
34 |
35 | // Custom routes here...
36 |
37 |
38 | // If a request to a URL doesn't match any of the custom routes above,
39 | // it is matched against Sails route blueprints. See `config/blueprints.js`
40 | // for configuration options and examples.
41 |
42 | };
43 |
--------------------------------------------------------------------------------
/config/session.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Session Configuration
3 | * (sails.config.session)
4 | *
5 | * Sails session integration leans heavily on the great work already done by
6 | * Express, but also unifies Socket.io with the Connect session store. It uses
7 | * Connect's cookie parser to normalize configuration differences between Express
8 | * and Socket.io and hooks into Sails' middleware interpreter to allow you to access
9 | * and auto-save to `req.session` with Socket.io the same way you would with Express.
10 | *
11 | * For more information on configuring the session, check out:
12 | * http://links.sailsjs.org/docs/config/session
13 | */
14 |
15 | module.exports.session = {
16 |
17 | // Session secret is automatically generated when your new app is created
18 | // Replace at your own risk in production-- you will invalidate the cookies of your users,
19 | // forcing them to log in again.
20 | secret: '1465467589bb673d7270f41819341469',
21 |
22 |
23 | // Set the session cookie expire time
24 | // The maxAge is set by milliseconds, the example below is for 24 hours
25 | //
26 | // cookie: {
27 | // maxAge: 24 * 60 * 60 * 1000
28 | // }
29 |
30 |
31 | // In production, uncomment the following lines to set up a shared redis session store
32 | // that can be shared across multiple Sails.js servers
33 | // adapter: 'redis',
34 | //
35 | // The following values are optional, if no options are set a redis instance running
36 | // on localhost is expected.
37 | // Read more about options at: https://github.com/visionmedia/connect-redis
38 | //
39 | // host: 'localhost',
40 | // port: 6379,
41 | // ttl: ,
42 | // db: 0,
43 | // pass:
44 | // prefix: 'sess:'
45 |
46 |
47 | // Uncomment the following lines to use your Mongo adapter as a session store
48 | // adapter: 'mongo',
49 | //
50 | // host: 'localhost',
51 | // port: 27017,
52 | // db: 'sails',
53 | // collection: 'sessions',
54 | //
55 | // Optional Values:
56 | //
57 | // # Note: url will override other connection settings
58 | // url: 'mongodb://user:pass@host:port/database/collection',
59 | //
60 | // username: '',
61 | // password: '',
62 | // auto_reconnect: false,
63 | // ssl: false,
64 | // stringify: true
65 |
66 | };
67 |
--------------------------------------------------------------------------------
/config/sockets.js:
--------------------------------------------------------------------------------
1 | /**
2 | * WebSocket Server Settings
3 | * (sails.config.sockets)
4 | *
5 | * These settings provide transparent access to the options for Sails'
6 | * encapsulated WebSocket server, as well as some additional Sails-specific
7 | * configuration layered on top.
8 | *
9 | * For more information on sockets configuration, including advanced config options, see:
10 | * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.sockets.html
11 | */
12 |
13 | module.exports.sockets = {
14 |
15 |
16 | /***************************************************************************
17 | * *
18 | * Node.js (and consequently Sails.js) apps scale horizontally. It's a *
19 | * powerful, efficient approach, but it involves a tiny bit of planning. At *
20 | * scale, you'll want to be able to copy your app onto multiple Sails.js *
21 | * servers and throw them behind a load balancer. *
22 | * *
23 | * One of the big challenges of scaling an application is that these sorts *
24 | * of clustered deployments cannot share memory, since they are on *
25 | * physically different machines. On top of that, there is no guarantee *
26 | * that a user will "stick" with the same server between requests (whether *
27 | * HTTP or sockets), since the load balancer will route each request to the *
28 | * Sails server with the most available resources. However that means that *
29 | * all room/pubsub/socket processing and shared memory has to be offloaded *
30 | * to a shared, remote messaging queue (usually Redis) *
31 | * *
32 | * Luckily, Socket.io (and consequently Sails.js) apps support Redis for *
33 | * sockets by default. To enable a remote redis pubsub server, uncomment *
34 | * the config below. *
35 | * *
36 | * Worth mentioning is that, if `adapter` config is `redis`, but host/port *
37 | * is left unset, Sails will try to connect to redis running on localhost *
38 | * via port 6379 *
39 | * *
40 | ***************************************************************************/
41 | // adapter: 'memory',
42 |
43 | //
44 | // -OR-
45 | //
46 |
47 | // adapter: 'socket.io-redis',
48 | // host: '127.0.0.1',
49 | // port: 6379,
50 | // db: 0,
51 | // pass: '',
52 |
53 |
54 |
55 | /***************************************************************************
56 | * *
57 | * Whether to expose a 'get /__getcookie' route with CORS support that sets *
58 | * a cookie (this is used by the sails.io.js socket client to get access to *
59 | * a 3rd party cookie and to enable sessions). *
60 | * *
61 | * Warning: Currently in this scenario, CORS settings apply to interpreted *
62 | * requests sent via a socket.io connection that used this cookie to *
63 | * connect, even for non-browser clients! (e.g. iOS apps, toasters, node.js *
64 | * unit tests) *
65 | * *
66 | ***************************************************************************/
67 |
68 | // grant3rdPartyCookie: true,
69 |
70 |
71 |
72 | /***************************************************************************
73 | * *
74 | * `beforeConnect` *
75 | * *
76 | * This custom beforeConnect function will be run each time BEFORE a new *
77 | * socket is allowed to connect, when the initial socket.io handshake is *
78 | * performed with the server. *
79 | * *
80 | * By default, when a socket tries to connect, Sails allows it, every time. *
81 | * (much in the same way any HTTP request is allowed to reach your routes. *
82 | * If no valid cookie was sent, a temporary session will be created for the *
83 | * connecting socket. *
84 | * *
85 | * If the cookie sent as part of the connection request doesn't match any *
86 | * known user session, a new user session is created for it. *
87 | * *
88 | * In most cases, the user would already have a cookie since they loaded *
89 | * the socket.io client and the initial HTML page you're building. *
90 | * *
91 | * However, in the case of cross-domain requests, it is possible to receive *
92 | * a connection upgrade request WITHOUT A COOKIE (for certain transports) *
93 | * In this case, there is no way to keep track of the requesting user *
94 | * between requests, since there is no identifying information to link *
95 | * him/her with a session. The sails.io.js client solves this by connecting *
96 | * to a CORS/jsonp endpoint first to get a 3rd party cookie(fortunately this*
97 | * works, even in Safari), then opening the connection. *
98 | * *
99 | * You can also pass along a ?cookie query parameter to the upgrade url, *
100 | * which Sails will use in the absence of a proper cookie e.g. (when *
101 | * connecting from the client): *
102 | * io.sails.connect('http://localhost:1337?cookie=smokeybear') *
103 | * *
104 | * Finally note that the user's cookie is NOT (and will never be) accessible*
105 | * from client-side javascript. Using HTTP-only cookies is crucial for your *
106 | * app's security. *
107 | * *
108 | ***************************************************************************/
109 | // beforeConnect: function(handshake, cb) {
110 | // // `true` allows the connection
111 | // return cb(null, true);
112 | //
113 | // // (`false` would reject the connection)
114 | // },
115 |
116 |
117 | /***************************************************************************
118 | * *
119 | * `afterDisconnect` *
120 | * *
121 | * This custom afterDisconnect function will be run each time a socket *
122 | * disconnects *
123 | * *
124 | ***************************************************************************/
125 | // afterDisconnect: function(session, socket, cb) {
126 | // // By default: do nothing.
127 | // return cb();
128 | // },
129 |
130 | /***************************************************************************
131 | * *
132 | * `transports` *
133 | * *
134 | * A array of allowed transport methods which the clients will try to use. *
135 | * On server environments that don't support sticky sessions, the "polling" *
136 | * transport should be disabled. *
137 | * *
138 | ***************************************************************************/
139 | // transports: ["polling", "websocket"]
140 |
141 | };
142 |
--------------------------------------------------------------------------------
/config/views.js:
--------------------------------------------------------------------------------
1 | /**
2 | * View Engine Configuration
3 | * (sails.config.views)
4 | *
5 | * Server-sent views are a classic and effective way to get your app up
6 | * and running. Views are normally served from controllers. Below, you can
7 | * configure your templating language/framework of choice and configure
8 | * Sails' layout support.
9 | *
10 | * For more information on views and layouts, check out:
11 | * http://links.sailsjs.org/docs/config/views
12 | */
13 |
14 | module.exports.views = {
15 |
16 | // View engine (aka template language)
17 | // to use for your app's *server-side* views
18 | //
19 | // Sails+Express supports all view engines which implement
20 | // TJ Holowaychuk's `consolidate.js`, including, but not limited to:
21 | //
22 | // ejs, jade, handlebars, mustache
23 | // underscore, hogan, haml, haml-coffee, dust
24 | // atpl, eco, ect, jazz, jqtpl, JUST, liquor, QEJS,
25 | // swig, templayed, toffee, walrus, & whiskers
26 |
27 | // For more options, check out the docs:
28 | // https://github.com/balderdashy/sails-wiki/blob/0.9/config.views.md#engine
29 |
30 | engine: 'ejs',
31 |
32 |
33 |
34 | // Layouts are simply top-level HTML templates you can use as wrappers
35 | // for your server-side views. If you're using ejs or jade, you can take advantage of
36 | // Sails' built-in `layout` support.
37 | //
38 | // When using a layout, when one of your views is served, it is injected into
39 | // the `body` partial defined in the layout. This lets you reuse header
40 | // and footer logic between views.
41 | //
42 | // NOTE: Layout support is only implemented for the `ejs` view engine!
43 | // For most other engines, it is not necessary, since they implement
44 | // partials/layouts themselves. In those cases, this config will be silently
45 | // ignored.
46 | //
47 | // The `layout` setting may be set to one of the following:
48 | //
49 | // If `false`, layouts will be disabled.
50 | // Otherwise, if a string is specified, it will be interpreted as the relative path
51 | // to your layout file from `views/` folder. (the file extension, ".ejs", should be omitted)
52 | //
53 |
54 | layout: 'layout'
55 |
56 |
57 |
58 | // Using Multiple Layouts with EJS
59 | //
60 | // If you're using the default engine, `ejs`, Sails supports the use of multiple
61 | // `layout` files. To take advantage of this, before rendering a view, override
62 | // the `layout` local in your controller by setting `res.locals.layout`.
63 | // (this is handy if you parts of your app's UI look completely different from each other)
64 | //
65 | // e.g. your default might be
66 | // layout: 'layouts/public'
67 | //
68 | // But you might override that in some of your controllers with:
69 | // layout: 'layouts/internal'
70 |
71 |
72 | };
73 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sails-react-example",
3 | "version": "0.3.0",
4 | "description": "Sails and React integration example. Also uses Bower for web package management and RequireJS for AMD.",
5 | "keywords": [],
6 | "dependencies": {
7 | "bower": "^1.3.3",
8 | "ejs": "2.3.4",
9 | "grunt": "0.4.5",
10 | "grunt-babel": "^6.0.0",
11 | "babel-preset-es2015": "^6.5.0",
12 | "babel-preset-react": "^6.5.0",
13 | "grunt-contrib-clean": "0.6.0",
14 | "grunt-contrib-coffee": "0.13.0",
15 | "grunt-contrib-concat": "0.5.1",
16 | "grunt-contrib-copy": "0.5.0",
17 | "grunt-contrib-cssmin": "0.9.0",
18 | "grunt-contrib-jst": "0.6.0",
19 | "grunt-contrib-less": "1.1.0",
20 | "grunt-contrib-uglify": "0.7.0",
21 | "grunt-contrib-watch": "0.5.3",
22 | "grunt-sails-linker": "~0.10.1",
23 | "grunt-sync": "0.2.4",
24 | "include-all": "~0.1.6",
25 | "rc": "1.0.1",
26 | "sails": "~0.12.0",
27 | "sails-disk": "~0.10.9"
28 | },
29 | "scripts": {
30 | "start": "node app.js",
31 | "debug": "node debug app.js"
32 | },
33 | "main": "app.js",
34 | "repository": {
35 | "type": "git",
36 | "url": "https://github.com/mixxen/sails-react-example"
37 | },
38 | "author": "Alex Cabello",
39 | "license": "MIT"
40 | }
41 |
--------------------------------------------------------------------------------
/tasks/README.md:
--------------------------------------------------------------------------------
1 | # About the `tasks` folder
2 |
3 | The `tasks` directory is a suite of Grunt tasks and their configurations, bundled for your convenience. The Grunt integration is mainly useful for bundling front-end assets, (like stylesheets, scripts, & markup templates) but it can also be used to run all kinds of development tasks, from browserify compilation to database migrations.
4 |
5 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, read on!
6 |
7 |
8 | ### How does this work?
9 |
10 | The asset pipeline bundled in Sails is a set of Grunt tasks configured with conventional defaults designed to make your project more consistent and productive.
11 |
12 | The entire front-end asset workflow in Sails is completely customizable-- while it provides some suggestions out of the box, Sails makes no pretense that it can anticipate all of the needs you'll encounter building the browser-based/front-end portion of your application. Who's to say you're even building an app for a browser?
13 |
14 |
15 |
16 | ### What tasks does Sails run automatically?
17 |
18 | Sails runs some of these tasks (the ones in the `tasks/register` folder) automatically when you run certain commands.
19 |
20 | ###### `sails lift`
21 |
22 | Runs the `default` task (`tasks/register/default.js`).
23 |
24 | ###### `sails lift --prod`
25 |
26 | Runs the `prod` task (`tasks/register/prod.js`).
27 |
28 | ###### `sails www`
29 |
30 | Runs the `build` task (`tasks/register/build.js`).
31 |
32 | ###### `sails www --prod` (production)
33 |
34 | Runs the `buildProd` task (`tasks/register/buildProd.js`).
35 |
36 |
37 | ### Can I customize this for SASS, Angular, client-side Jade templates, etc?
38 |
39 | You can modify, omit, or replace any of these Grunt tasks to fit your requirements. You can also add your own Grunt tasks- just add a `someTask.js` file in the `grunt/config` directory to configure the new task, then register it with the appropriate parent task(s) (see files in `grunt/register/*.js`).
40 |
41 |
42 | ### Do I have to use Grunt?
43 |
44 | Nope! To disable Grunt integration in Sails, just delete your Gruntfile or disable the Grunt hook.
45 |
46 |
47 | ### What if I'm not building a web frontend?
48 |
49 | That's ok! A core tenant of Sails is client-agnosticism-- it's especially designed for building APIs used by all sorts of clients; native Android/iOS/Cordova, serverside SDKs, etc.
50 |
51 | You can completely disable Grunt by following the instructions above.
52 |
53 | If you still want to use Grunt for other purposes, but don't want any of the default web front-end stuff, just delete your project's `assets` folder and remove the front-end oriented tasks from the `grunt/register` and `grunt/config` folders. You can also run `sails new myCoolApi --no-frontend` to omit the `assets` folder and front-end-oriented Grunt tasks for future projects. You can also replace your `sails-generate-frontend` module with alternative community generators, or create your own. This allows `sails new` to create the boilerplate for native iOS apps, Android apps, Cordova apps, SteroidsJS apps, etc.
54 |
55 |
--------------------------------------------------------------------------------
/tasks/config/babel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Compile JSX files to JavaScript.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Compiles jsx files from `assest/js` into Javascript and places them into
7 | * `.tmp/public/js` directory.
8 | *
9 | */
10 | module.exports = function(grunt) {
11 |
12 | grunt.config.set('babel', {
13 | dev: {
14 | options: {
15 | presets: ['react']
16 | },
17 | files: [{
18 | expand: true,
19 | cwd: 'assets/js/',
20 | src: ['**/*.jsx'],
21 | dest: '.tmp/public/js/',
22 | ext: '.js'
23 | }]
24 | }
25 | });
26 |
27 | grunt.loadNpmTasks('grunt-babel');
28 | };
29 |
--------------------------------------------------------------------------------
/tasks/config/clean.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Clean files and folders.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * This grunt task is configured to clean out the contents in the .tmp/public of your
7 | * sails project.
8 | *
9 | * For usage docs see:
10 | * https://github.com/gruntjs/grunt-contrib-clean
11 | */
12 | module.exports = function(grunt) {
13 |
14 | grunt.config.set('clean', {
15 | dev: ['.tmp/public/**'],
16 | build: ['www']
17 | });
18 |
19 | grunt.loadNpmTasks('grunt-contrib-clean');
20 | };
21 |
--------------------------------------------------------------------------------
/tasks/config/coffee.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Compile CoffeeScript files to JavaScript.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Compiles coffeeScript files from `assest/js` into Javascript and places them into
7 | * `.tmp/public/js` directory.
8 | *
9 | * For usage docs see:
10 | * https://github.com/gruntjs/grunt-contrib-coffee
11 | */
12 | module.exports = function(grunt) {
13 |
14 | grunt.config.set('coffee', {
15 | dev: {
16 | options: {
17 | bare: true,
18 | sourceMap: true,
19 | sourceRoot: './'
20 | },
21 | files: [{
22 | expand: true,
23 | cwd: 'assets/js/',
24 | src: ['**/*.coffee'],
25 | dest: '.tmp/public/js/',
26 | ext: '.js'
27 | }]
28 | }
29 | });
30 |
31 | grunt.loadNpmTasks('grunt-contrib-coffee');
32 | };
33 |
--------------------------------------------------------------------------------
/tasks/config/concat.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Concatenate files.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Concatenates files javascript and css from a defined array. Creates concatenated files in
7 | * .tmp/public/contact directory
8 | * [concat](https://github.com/gruntjs/grunt-contrib-concat)
9 | *
10 | * For usage docs see:
11 | * https://github.com/gruntjs/grunt-contrib-concat
12 | */
13 | module.exports = function(grunt) {
14 |
15 | grunt.config.set('concat', {
16 | js: {
17 | src: require('../pipeline').jsFilesToInject,
18 | dest: '.tmp/public/concat/production.js'
19 | },
20 | css: {
21 | src: require('../pipeline').cssFilesToInject,
22 | dest: '.tmp/public/concat/production.css'
23 | }
24 | });
25 |
26 | grunt.loadNpmTasks('grunt-contrib-concat');
27 | };
28 |
--------------------------------------------------------------------------------
/tasks/config/copy.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copy files and folders.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * # dev task config
7 | * Copies all directories and files, exept coffescript and less fiels, from the sails
8 | * assets folder into the .tmp/public directory.
9 | *
10 | * # build task config
11 | * Copies all directories nd files from the .tmp/public directory into a www directory.
12 | *
13 | * For usage docs see:
14 | * https://github.com/gruntjs/grunt-contrib-copy
15 | */
16 | module.exports = function(grunt) {
17 |
18 | grunt.config.set('copy', {
19 | dev: {
20 | files: [{
21 | expand: true,
22 | cwd: './assets',
23 | src: ['**/*.!(coffee|less)', '!**/*.jsx'],
24 | dest: '.tmp/public'
25 | }]
26 | },
27 | build: {
28 | files: [{
29 | expand: true,
30 | cwd: '.tmp/public',
31 | src: ['**/*'],
32 | dest: 'www'
33 | }]
34 | }
35 | });
36 |
37 | grunt.loadNpmTasks('grunt-contrib-copy');
38 | };
39 |
--------------------------------------------------------------------------------
/tasks/config/cssmin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Compress CSS files.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Minifies css files and places them into .tmp/public/min directory.
7 | *
8 | * For usage docs see:
9 | * https://github.com/gruntjs/grunt-contrib-cssmin
10 | */
11 | module.exports = function(grunt) {
12 |
13 | grunt.config.set('cssmin', {
14 | dist: {
15 | src: ['.tmp/public/concat/production.css'],
16 | dest: '.tmp/public/min/production.min.css'
17 | }
18 | });
19 |
20 | grunt.loadNpmTasks('grunt-contrib-cssmin');
21 | };
22 |
--------------------------------------------------------------------------------
/tasks/config/jst.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Precompiles Underscore templates to a `.jst` file.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * (i.e. basically it takes HTML files and turns them into tiny little
7 | * javascript functions that you pass data to and return HTML. This can
8 | * speed up template rendering on the client, and reduce bandwidth usage.)
9 | *
10 | * For usage docs see:
11 | * https://github.com/gruntjs/grunt-contrib-jst
12 | *
13 | */
14 |
15 | module.exports = function(grunt) {
16 |
17 | var templateFilesToInject = [
18 | 'templates/**/*.html'
19 | ];
20 |
21 | grunt.config.set('jst', {
22 | dev: {
23 |
24 | // To use other sorts of templates, specify a regexp like the example below:
25 | // options: {
26 | // templateSettings: {
27 | // interpolate: /\{\{(.+?)\}\}/g
28 | // }
29 | // },
30 |
31 | // Note that the interpolate setting above is simply an example of overwriting lodash's
32 | // default interpolation. If you want to parse templates with the default _.template behavior
33 | // (i.e. using ), there's no need to overwrite `templateSettings.interpolate`.
34 |
35 |
36 | files: {
37 | // e.g.
38 | // 'relative/path/from/gruntfile/to/compiled/template/destination' : ['relative/path/to/sourcefiles/**/*.html']
39 | '.tmp/public/jst.js': require('../pipeline').templateFilesToInject
40 | }
41 | }
42 | });
43 |
44 | grunt.loadNpmTasks('grunt-contrib-jst');
45 | };
46 |
--------------------------------------------------------------------------------
/tasks/config/less.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Compiles LESS files into CSS.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Only the `assets/styles/importer.less` is compiled.
7 | * This allows you to control the ordering yourself, i.e. import your
8 | * dependencies, mixins, variables, resets, etc. before other stylesheets)
9 | *
10 | * For usage docs see:
11 | * https://github.com/gruntjs/grunt-contrib-less
12 | */
13 | module.exports = function(grunt) {
14 |
15 | grunt.config.set('less', {
16 | dev: {
17 | files: [{
18 | expand: true,
19 | cwd: 'assets/styles/',
20 | src: ['importer.less'],
21 | dest: '.tmp/public/styles/',
22 | ext: '.css'
23 | }]
24 | }
25 | });
26 |
27 | grunt.loadNpmTasks('grunt-contrib-less');
28 | };
29 |
--------------------------------------------------------------------------------
/tasks/config/sails-linker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Autoinsert script tags (or other filebased tags) in an html file.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Automatically inject ',
22 | appRoot: '.tmp/public'
23 | },
24 | files: {
25 | '.tmp/public/**/*.html': require('../pipeline').jsFilesToInject,
26 | 'views/**/*.html': require('../pipeline').jsFilesToInject,
27 | 'views/**/*.ejs': require('../pipeline').jsFilesToInject
28 | }
29 | },
30 |
31 | devJsRelative: {
32 | options: {
33 | startTag: '',
34 | endTag: '',
35 | fileTmpl: '',
36 | appRoot: '.tmp/public',
37 | relative: true
38 | },
39 | files: {
40 | '.tmp/public/**/*.html': require('../pipeline').jsFilesToInject,
41 | 'views/**/*.html': require('../pipeline').jsFilesToInject,
42 | 'views/**/*.ejs': require('../pipeline').jsFilesToInject
43 | }
44 | },
45 |
46 | prodJs: {
47 | options: {
48 | startTag: '',
49 | endTag: '',
50 | fileTmpl: '',
51 | appRoot: '.tmp/public'
52 | },
53 | files: {
54 | '.tmp/public/**/*.html': ['.tmp/public/min/production.min.js'],
55 | 'views/**/*.html': ['.tmp/public/min/production.min.js'],
56 | 'views/**/*.ejs': ['.tmp/public/min/production.min.js']
57 | }
58 | },
59 |
60 | prodJsRelative: {
61 | options: {
62 | startTag: '',
63 | endTag: '',
64 | fileTmpl: '',
65 | appRoot: '.tmp/public',
66 | relative: true
67 | },
68 | files: {
69 | '.tmp/public/**/*.html': ['.tmp/public/min/production.min.js'],
70 | 'views/**/*.html': ['.tmp/public/min/production.min.js'],
71 | 'views/**/*.ejs': ['.tmp/public/min/production.min.js']
72 | }
73 | },
74 |
75 | devStyles: {
76 | options: {
77 | startTag: '',
78 | endTag: '',
79 | fileTmpl: '',
80 | appRoot: '.tmp/public'
81 | },
82 |
83 | files: {
84 | '.tmp/public/**/*.html': require('../pipeline').cssFilesToInject,
85 | 'views/**/*.html': require('../pipeline').cssFilesToInject,
86 | 'views/**/*.ejs': require('../pipeline').cssFilesToInject
87 | }
88 | },
89 |
90 | devStylesRelative: {
91 | options: {
92 | startTag: '',
93 | endTag: '',
94 | fileTmpl: '',
95 | appRoot: '.tmp/public',
96 | relative: true
97 | },
98 |
99 | files: {
100 | '.tmp/public/**/*.html': require('../pipeline').cssFilesToInject,
101 | 'views/**/*.html': require('../pipeline').cssFilesToInject,
102 | 'views/**/*.ejs': require('../pipeline').cssFilesToInject
103 | }
104 | },
105 |
106 | prodStyles: {
107 | options: {
108 | startTag: '',
109 | endTag: '',
110 | fileTmpl: '',
111 | appRoot: '.tmp/public'
112 | },
113 | files: {
114 | '.tmp/public/index.html': ['.tmp/public/min/production.min.css'],
115 | 'views/**/*.html': ['.tmp/public/min/production.min.css'],
116 | 'views/**/*.ejs': ['.tmp/public/min/production.min.css']
117 | }
118 | },
119 |
120 | prodStylesRelative: {
121 | options: {
122 | startTag: '',
123 | endTag: '',
124 | fileTmpl: '',
125 | appRoot: '.tmp/public',
126 | relative: true
127 | },
128 | files: {
129 | '.tmp/public/index.html': ['.tmp/public/min/production.min.css'],
130 | 'views/**/*.html': ['.tmp/public/min/production.min.css'],
131 | 'views/**/*.ejs': ['.tmp/public/min/production.min.css']
132 | }
133 | },
134 |
135 | // Bring in JST template object
136 | devTpl: {
137 | options: {
138 | startTag: '',
139 | endTag: '',
140 | fileTmpl: '',
141 | appRoot: '.tmp/public'
142 | },
143 | files: {
144 | '.tmp/public/index.html': ['.tmp/public/jst.js'],
145 | 'views/**/*.html': ['.tmp/public/jst.js'],
146 | 'views/**/*.ejs': ['.tmp/public/jst.js']
147 | }
148 | },
149 |
150 | devJsJade: {
151 | options: {
152 | startTag: '// SCRIPTS',
153 | endTag: '// SCRIPTS END',
154 | fileTmpl: 'script(src="%s")',
155 | appRoot: '.tmp/public'
156 | },
157 | files: {
158 | 'views/**/*.jade': require('../pipeline').jsFilesToInject
159 | }
160 | },
161 |
162 | devJsRelativeJade: {
163 | options: {
164 | startTag: '// SCRIPTS',
165 | endTag: '// SCRIPTS END',
166 | fileTmpl: 'script(src="%s")',
167 | appRoot: '.tmp/public',
168 | relative: true
169 | },
170 | files: {
171 | 'views/**/*.jade': require('../pipeline').jsFilesToInject
172 | }
173 | },
174 |
175 | prodJsJade: {
176 | options: {
177 | startTag: '// SCRIPTS',
178 | endTag: '// SCRIPTS END',
179 | fileTmpl: 'script(src="%s")',
180 | appRoot: '.tmp/public'
181 | },
182 | files: {
183 | 'views/**/*.jade': ['.tmp/public/min/production.min.js']
184 | }
185 | },
186 |
187 | prodJsRelativeJade: {
188 | options: {
189 | startTag: '// SCRIPTS',
190 | endTag: '// SCRIPTS END',
191 | fileTmpl: 'script(src="%s")',
192 | appRoot: '.tmp/public',
193 | relative: true
194 | },
195 | files: {
196 | 'views/**/*.jade': ['.tmp/public/min/production.min.js']
197 | }
198 | },
199 |
200 | devStylesJade: {
201 | options: {
202 | startTag: '// STYLES',
203 | endTag: '// STYLES END',
204 | fileTmpl: 'link(rel="stylesheet", href="%s")',
205 | appRoot: '.tmp/public'
206 | },
207 |
208 | files: {
209 | 'views/**/*.jade': require('../pipeline').cssFilesToInject
210 | }
211 | },
212 |
213 | devStylesRelativeJade: {
214 | options: {
215 | startTag: '// STYLES',
216 | endTag: '// STYLES END',
217 | fileTmpl: 'link(rel="stylesheet", href="%s")',
218 | appRoot: '.tmp/public',
219 | relative: true
220 | },
221 |
222 | files: {
223 | 'views/**/*.jade': require('../pipeline').cssFilesToInject
224 | }
225 | },
226 |
227 | prodStylesJade: {
228 | options: {
229 | startTag: '// STYLES',
230 | endTag: '// STYLES END',
231 | fileTmpl: 'link(rel="stylesheet", href="%s")',
232 | appRoot: '.tmp/public'
233 | },
234 | files: {
235 | 'views/**/*.jade': ['.tmp/public/min/production.min.css']
236 | }
237 | },
238 |
239 | prodStylesRelativeJade: {
240 | options: {
241 | startTag: '// STYLES',
242 | endTag: '// STYLES END',
243 | fileTmpl: 'link(rel="stylesheet", href="%s")',
244 | appRoot: '.tmp/public',
245 | relative: true
246 | },
247 | files: {
248 | 'views/**/*.jade': ['.tmp/public/min/production.min.css']
249 | }
250 | },
251 |
252 | // Bring in JST template object
253 | devTplJade: {
254 | options: {
255 | startTag: '// TEMPLATES',
256 | endTag: '// TEMPLATES END',
257 | fileTmpl: 'script(type="text/javascript", src="%s")',
258 | appRoot: '.tmp/public'
259 | },
260 | files: {
261 | 'views/**/*.jade': ['.tmp/public/jst.js']
262 | }
263 | }
264 | });
265 |
266 | grunt.loadNpmTasks('grunt-sails-linker');
267 | };
268 |
--------------------------------------------------------------------------------
/tasks/config/sync.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A grunt task to keep directories in sync. It is very similar to grunt-contrib-copy
3 | * but tries to copy only those files that has actually changed.
4 | *
5 | * ---------------------------------------------------------------
6 | *
7 | * Synchronize files from the `assets` folder to `.tmp/public`,
8 | * smashing anything that's already there.
9 | *
10 | * For usage docs see:
11 | * https://github.com/tomusdrw/grunt-sync
12 | *
13 | */
14 | module.exports = function(grunt) {
15 |
16 | grunt.config.set('sync', {
17 | dev: {
18 | files: [{
19 | cwd: './assets',
20 | src: ['**/*.!(coffee)', '!**/*.jsx'],
21 | dest: '.tmp/public'
22 | }]
23 | }
24 | });
25 |
26 | grunt.loadNpmTasks('grunt-sync');
27 | };
28 |
--------------------------------------------------------------------------------
/tasks/config/uglify.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Minify files with UglifyJS.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Minifies client-side javascript `assets`.
7 | *
8 | * For usage docs see:
9 | * https://github.com/gruntjs/grunt-contrib-uglify
10 | *
11 | */
12 | module.exports = function(grunt) {
13 |
14 | grunt.config.set('uglify', {
15 | dist: {
16 | src: ['.tmp/public/concat/production.js'],
17 | dest: '.tmp/public/min/production.min.js'
18 | }
19 | });
20 |
21 | grunt.loadNpmTasks('grunt-contrib-uglify');
22 | };
23 |
--------------------------------------------------------------------------------
/tasks/config/watch.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Run predefined tasks whenever watched file patterns are added, changed or deleted.
3 | *
4 | * ---------------------------------------------------------------
5 | *
6 | * Watch for changes on
7 | * - files in the `assets` folder
8 | * - the `tasks/pipeline.js` file
9 | * and re-run the appropriate tasks.
10 | *
11 | * For usage docs see:
12 | * https://github.com/gruntjs/grunt-contrib-watch
13 | *
14 | */
15 | module.exports = function(grunt) {
16 |
17 | grunt.config.set('watch', {
18 | api: {
19 |
20 | // API files to watch:
21 | files: ['api/**/*']
22 | },
23 | assets: {
24 |
25 | // Assets to watch:
26 | files: ['assets/**/*', 'tasks/pipeline.js'],
27 |
28 | // When assets are changed:
29 | tasks: ['syncAssets' , 'linkAssets']
30 | }
31 | });
32 |
33 | grunt.loadNpmTasks('grunt-contrib-watch');
34 | };
35 |
--------------------------------------------------------------------------------
/tasks/pipeline.js:
--------------------------------------------------------------------------------
1 | /**
2 | * grunt/pipeline.js
3 | *
4 | * The order in which your css, javascript, and template files should be
5 | * compiled and linked from your views and static HTML files.
6 | *
7 | * (Note that you can take advantage of Grunt-style wildcard/glob/splat expressions
8 | * for matching multiple files.)
9 | */
10 |
11 |
12 |
13 | // CSS files to inject in order
14 | //
15 | // (if you're using LESS with the built-in default config, you'll want
16 | // to change `assets/styles/importer.less` instead.)
17 | var cssFilesToInject = [
18 | 'bower_components/bootstrap/dist/css/bootstrap.css',
19 | 'bower_components/bootstrap/dist/css/bootstrap-theme.css',
20 | 'styles/**/*.css'
21 | ];
22 |
23 |
24 | // Client-side javascript files to inject in order
25 | // (uses Grunt-style wildcard/glob/splat expressions)
26 | var jsFilesToInject = [
27 |
28 | // Dependencies like sails.io.js, jQuery, or Angular
29 | // are brought in here
30 | 'js/dependencies/**/*.js',
31 |
32 | // All of the rest of your client-side js files
33 | // will be injected here in no particular order.
34 | // 'js/**/*.js'
35 |
36 | // file loading is handled by requirejs
37 | 'bower_components/requirejs/require.js',
38 | ];
39 |
40 |
41 | // Client-side HTML templates are injected using the sources below
42 | // The ordering of these templates shouldn't matter.
43 | // (uses Grunt-style wildcard/glob/splat expressions)
44 | //
45 | // By default, Sails uses JST templates and precompiles them into
46 | // functions for you. If you want to use jade, handlebars, dust, etc.,
47 | // with the linker, no problem-- you'll just want to make sure the precompiled
48 | // templates get spit out to the same file. Be sure and check out `tasks/README.md`
49 | // for information on customizing and installing new tasks.
50 | var templateFilesToInject = [
51 | 'templates/**/*.html'
52 | ];
53 |
54 |
55 |
56 | // Prefix relative paths to source files so they point to the proper locations
57 | // (i.e. where the other Grunt tasks spit them out, or in some cases, where
58 | // they reside in the first place)
59 | module.exports.cssFilesToInject = cssFilesToInject.map(function(path) {
60 | return '.tmp/public/' + path;
61 | });
62 | module.exports.jsFilesToInject = jsFilesToInject.map(function(path) {
63 | return '.tmp/public/' + path;
64 | });
65 | module.exports.templateFilesToInject = templateFilesToInject.map(function(path) {
66 | return 'assets/' + path;
67 | });
68 |
--------------------------------------------------------------------------------
/tasks/register/build.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('build', [
3 | 'compileAssets',
4 | 'linkAssetsBuild',
5 | 'clean:build',
6 | 'copy:build'
7 | ]);
8 | };
9 |
--------------------------------------------------------------------------------
/tasks/register/buildProd.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('buildProd', [
3 | 'compileAssets',
4 | 'concat',
5 | 'uglify',
6 | 'cssmin',
7 | 'linkAssetsBuildProd',
8 | 'clean:build',
9 | 'copy:build'
10 | ]);
11 | };
12 |
--------------------------------------------------------------------------------
/tasks/register/compileAssets.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('compileAssets', [
3 | 'clean:dev',
4 | 'jst:dev',
5 | 'less:dev',
6 | 'copy:dev',
7 | 'coffee:dev',
8 | 'babel:dev'
9 | ]);
10 | };
11 |
--------------------------------------------------------------------------------
/tasks/register/default.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('default', ['compileAssets', 'linkAssets', 'watch']);
3 | };
4 |
--------------------------------------------------------------------------------
/tasks/register/linkAssets.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('linkAssets', [
3 | 'sails-linker:devJs',
4 | 'sails-linker:devStyles',
5 | 'sails-linker:devTpl',
6 | 'sails-linker:devJsJade',
7 | 'sails-linker:devStylesJade',
8 | 'sails-linker:devTplJade'
9 | ]);
10 | };
11 |
--------------------------------------------------------------------------------
/tasks/register/linkAssetsBuild.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('linkAssetsBuild', [
3 | 'sails-linker:devJsRelative',
4 | 'sails-linker:devStylesRelative',
5 | 'sails-linker:devTpl',
6 | 'sails-linker:devJsRelativeJade',
7 | 'sails-linker:devStylesRelativeJade',
8 | 'sails-linker:devTplJade'
9 | ]);
10 | };
11 |
--------------------------------------------------------------------------------
/tasks/register/linkAssetsBuildProd.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('linkAssetsBuildProd', [
3 | 'sails-linker:prodJsRelative',
4 | 'sails-linker:prodStylesRelative',
5 | 'sails-linker:devTpl',
6 | 'sails-linker:prodJsRelativeJade',
7 | 'sails-linker:prodStylesRelativeJade',
8 | 'sails-linker:devTplJade'
9 | ]);
10 | };
11 |
--------------------------------------------------------------------------------
/tasks/register/prod.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('prod', [
3 | 'compileAssets',
4 | 'concat',
5 | 'uglify',
6 | 'cssmin',
7 | 'sails-linker:prodJs',
8 | 'sails-linker:prodStyles',
9 | 'sails-linker:devTpl',
10 | 'sails-linker:prodJsJade',
11 | 'sails-linker:prodStylesJade',
12 | 'sails-linker:devTplJade'
13 | ]);
14 | };
15 |
--------------------------------------------------------------------------------
/tasks/register/syncAssets.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.registerTask('syncAssets', [
3 | 'jst:dev',
4 | 'less:dev',
5 | 'sync:dev',
6 | 'coffee:dev',
7 | 'babel:dev'
8 | ]);
9 | };
10 |
--------------------------------------------------------------------------------
/todosmvc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mixxen/sails-react-example/d9259d7bd84fd41e78eb66b6ce8f6e4d54204e08/todosmvc.png
--------------------------------------------------------------------------------
/views/403.ejs:
--------------------------------------------------------------------------------
1 |
2 |
36 |
37 |
38 | Forbidden
39 |
40 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Forbidden
55 |
56 |
57 | <% if (typeof error !== 'undefined') { %>
58 | <%= error %>
59 | <% } else { %>
60 | You don't have permission to see the page you're trying to reach.
61 | <% } %>
62 |
69 | A team of highly trained sea bass is working on this as we speak.
70 | If the problem persists, please contact the system administrator and inform them of the time that the error occured, and anything you might have done that may have caused the error.
71 |