├── .dockerignore
├── .editorconfig
├── .env
├── .gitignore
├── CHANGELOG.md
├── README.md
├── app
├── app.ts
├── config
│ ├── default.json
│ └── production.json
├── hooks
│ └── index.ts
├── middleware
│ ├── index.ts
│ ├── logger.ts
│ ├── not-found-handler.ts
│ └── webpack-hot.ts
├── models
│ ├── message.ts
│ └── user.ts
├── service
│ ├── authentication
│ │ ├── hooks
│ │ │ └── index.ts
│ │ └── index.ts
│ ├── index.ts
│ ├── message
│ │ ├── hooks
│ │ │ └── index.ts
│ │ └── index.ts
│ └── user
│ │ ├── hooks
│ │ └── index.ts
│ │ └── index.ts
└── webpack
│ └── webpack.server.common.ts
├── client
├── app
│ ├── 404
│ │ ├── 404.component.html
│ │ ├── 404.component.scss
│ │ └── 404.component.ts
│ ├── app.component.html
│ ├── app.component.scss
│ ├── app.component.ts
│ ├── app.global.scss
│ ├── app.module.ts
│ ├── app.routes.ts
│ ├── app.service.ts
│ ├── env.ts
│ ├── index.ts
│ ├── login
│ │ ├── login.component.html
│ │ ├── login.component.scss
│ │ ├── login.component.ts
│ │ └── login.service.ts
│ ├── meta.json
│ ├── module
│ │ ├── dashboard
│ │ │ ├── dashboard.component.html
│ │ │ ├── dashboard.component.ts
│ │ │ ├── dashboard.module.ts
│ │ │ ├── dashboard.routes.ts
│ │ │ └── index.ts
│ │ ├── home
│ │ │ ├── home.component.html
│ │ │ └── home.component.ts
│ │ ├── index.ts
│ │ ├── message
│ │ │ ├── index.ts
│ │ │ ├── message.component.html
│ │ │ ├── message.component.ts
│ │ │ ├── message.module.ts
│ │ │ ├── message.routes.ts
│ │ │ └── message.service.ts
│ │ ├── mod.module.ts
│ │ ├── module.component.html
│ │ ├── module.component.scss
│ │ ├── module.component.ts
│ │ ├── module.routes.ts
│ │ ├── setting
│ │ │ ├── password.component.html
│ │ │ ├── password.component.scss
│ │ │ ├── password.component.ts
│ │ │ ├── profile.component.html
│ │ │ ├── profile.component.ts
│ │ │ ├── setting.module.ts
│ │ │ └── setting.routes.ts
│ │ └── user
│ │ │ ├── dialog
│ │ │ ├── addUser.html
│ │ │ └── addUser.scss
│ │ │ ├── index.ts
│ │ │ ├── user.component.html
│ │ │ ├── user.component.scss
│ │ │ ├── user.component.ts
│ │ │ ├── user.module.ts
│ │ │ ├── user.routes.ts
│ │ │ └── user.service.ts
│ ├── shared
│ │ ├── footer
│ │ │ ├── footer.component.html
│ │ │ ├── footer.component.scss
│ │ │ └── footer.component.ts
│ │ ├── index.ts
│ │ ├── material.scss
│ │ ├── module.service.ts
│ │ ├── navigation.service.ts
│ │ └── version.service.ts
│ ├── signup
│ │ ├── signup.component.html
│ │ ├── signup.component.scss
│ │ ├── signup.component.ts
│ │ └── signup.service.ts
│ └── widgets
│ │ ├── index.ts
│ │ └── todo
│ │ ├── index.ts
│ │ ├── todo.html
│ │ └── todo.ts
├── assets
│ ├── favicon.ico
│ └── icon
│ │ ├── android-icon-144x144.png
│ │ ├── android-icon-192x192.png
│ │ ├── android-icon-36x36.png
│ │ ├── android-icon-48x48.png
│ │ ├── android-icon-72x72.png
│ │ ├── android-icon-96x96.png
│ │ ├── apple-icon-114x114.png
│ │ ├── apple-icon-120x120.png
│ │ ├── apple-icon-144x144.png
│ │ ├── apple-icon-152x152.png
│ │ ├── apple-icon-180x180.png
│ │ ├── apple-icon-57x57.png
│ │ ├── apple-icon-60x60.png
│ │ ├── apple-icon-72x72.png
│ │ ├── apple-icon-76x76.png
│ │ ├── apple-icon-precomposed.png
│ │ ├── apple-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon-96x96.png
│ │ ├── favicon.ico
│ │ ├── ms-icon-144x144.png
│ │ ├── ms-icon-150x150.png
│ │ ├── ms-icon-310x310.png
│ │ └── ms-icon-70x70.png
├── config
│ ├── config.common.ts
│ ├── config.dev.ts
│ ├── config.prod.ts
│ ├── config.ts
│ ├── empty.ts
│ ├── helpers.ts
│ ├── html-elements-plugin
│ │ └── index.ts
│ ├── html-head-config.ts
│ ├── resource-override.ts
│ ├── webpack.common.ts
│ ├── webpack.dev.ts
│ └── webpack.prod.ts
├── custom-typings.d.ts
├── index.html
├── main.aot.ts
├── main.ts
├── polyfills.ts
└── reducer
│ ├── index.ts
│ └── message.ts
├── docker
├── dev.dockerfile
├── docker-compose.dev.yml
├── docker-compose.prod.yml
└── prod.dockerfile
├── package.json
├── process.yml
├── server.ts
├── tsconfig.client.json
├── tsconfig.server.json
├── tslint.json
├── webpack.config.js
└── yarn.lock
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | COMPOSE_PROJECT_NAME=famn
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Dependency directory
11 | # Commenting this out is preferred by some people, see
12 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
13 | /node_modules/
14 | /typings/
15 |
16 | # Users Environment Variables
17 | .DS_Store
18 | .lock-wscript
19 | .tsdrc
20 | .typingsrc
21 | .awcache
22 | yarn-error.log
23 | npm-debug.log
24 |
25 |
26 | # IDE configuration files
27 | .idea
28 | .vscode
29 | *.iml
30 |
31 | # target
32 | dist
33 | dll
34 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 0.1.0 (2017-01-21)
2 |
3 | ### Bug Fix
4 |
5 | - Change 404 page style
6 |
7 | ### Features
8 |
9 | - User can change password
10 | - User can update profile
11 | - Add createdAt, updatedAt in mongoose user schema
12 |
13 | # 0.1.1 (2017-02-21)
14 |
15 | ### Features
16 |
17 | - Update angular2 to 2.4.8
18 | - Introducing Webpack DLL
19 | - Introducing AOT (Not passed test yet)
20 |
21 | # 0.1.2 (2017-03-10)
22 |
23 | ### Features
24 |
25 | - introduce feathers-permissions to add user authorization
26 |
27 | # 0.1.3 (2017-03-17)
28 |
29 | ### Features
30 |
31 | - send message in message panel
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # famn
2 |
3 | Famn is an Angular2 application framework with both client side and server side integrated.
4 | I have been exploring for such an Angular2 [MEAN](http://mean.io) for a while but w/o an ideal solution, so I write it.
5 |
6 | Famn stands for [Feathers](http://feathersjs.com/), [Angular2](https://angular.io), [MongoDB](https://www.mongodb.com/), and [Node.js](https://nodejs.org/en/)
7 |
8 | Famn borrowed much from [angular2-webpack-starter](https://github.com/AngularClass/angular2-webpack-starter), [@angular/material](https://github.com/angular/material2), [ng2-material](https://github.com/justindujardin/ng2-material)
9 |
10 | *IMPORTANT* This project has no commercial level of support and it's suggested to use in development for quick prototype. PR is welcome to make it go further.
11 |
12 |
13 | ### Features
14 |
15 | - Angular 2 + typescript
16 | - Webpack for both client and server side
17 | - Feathers is to provide realtime service
18 | - All websocket based communications
19 | - MongoDB and mongoose model
20 | - Ngrx/store for state management
21 | - HMR in development
22 | - Material design
23 | - Docker based
24 |
25 | ### Development
26 |
27 | #### local
28 |
29 | ```sh
30 | # prepare environment
31 | npm i nodemon ts-node typescript@2.0
32 |
33 | # or use yarn
34 | yarn add nodemon ts-node typescript@2.0
35 |
36 | # build client code
37 | yarn run build:client:dev
38 |
39 | # start server with webpack hmr
40 | yarn run start:hmr
41 | ```
42 |
43 | #### docker (recommended)
44 |
45 | ```sh
46 | # docker way which is recommended
47 | docker-compose -f ./docker/docker-compose.dev.yml up --build
48 |
49 | # real time service, check the new message in message module after running below command
50 | curl -H 'Content-Type: application/json' \
51 | --data-binary '{ "email": "yourname@yourdomain.com", "message": "Hello FAMN" }' \
52 | http://localhost:3030/messages/'
53 | ```
54 |
55 | Go to `http://localhost:3030` with default created user `mo@po.da`, password `do`
56 |
57 | ### Deploy
58 |
59 | ```sh
60 | docker-compose -f ./docker/docker-compose.prod.yml up --build -d
61 | ```
62 |
63 | ### Other commands
64 |
65 | #### build
66 |
67 | ```sh
68 | # build client for dev
69 | yarn run build:client:dev
70 | # build client for prod
71 | yarn run build:client:prod
72 | # build client with AOT for prod
73 | yarn run build:client:aot:prod
74 | # build server for prod
75 | yarn run build:server:prod
76 | ```
77 |
78 |
79 |
80 | ### To do
81 |
82 | - ( ) CLI for project initialization
83 | - (*) user authorization
84 | - (*) robust material design data-table (ag-grid)
85 | - ( ) charts
86 | - ( ) unit test
87 |
--------------------------------------------------------------------------------
/app/app.ts:
--------------------------------------------------------------------------------
1 | import * as chalk from 'chalk'
2 | import * as path from 'path'
3 | import * as compress from 'compression'
4 | import * as cors from 'cors'
5 | import * as bodyParser from 'body-parser'
6 | import * as mongoose from 'mongoose'
7 | const feathers = require('feathers')
8 | const serveStatic = require('feathers').static
9 | const conf = require('feathers-configuration')
10 | const hooks = require('feathers-hooks')
11 | const rest = require('feathers-rest')
12 | const socketio = require('feathers-socketio')
13 | const handler = require('feathers-errors/handler')
14 |
15 | import service from './service'
16 | import middleware from './middleware'
17 |
18 | const app = feathers()
19 |
20 |
21 | // TO-FIX
22 | // Enable webpack-hot-middleware here for development
23 | if (process.env.NODE_ENV === 'development' && process.env.HMR) {
24 | const webpackdev = require('./middleware/webpack-hot')
25 | app.configure(webpackdev.default)
26 | }
27 |
28 | app.configure(conf());
29 |
30 | (mongoose as any).Promise = global.Promise
31 | const config = app.get('mongodb')
32 | const endpoint = `mongodb://${config.server.host}:${config.server.port}/${config.db}`
33 |
34 | mongoose.connect(endpoint)
35 | mongoose.connection.on('error', err => {
36 | console.error('connection error: ', err)
37 | process.exit(1)
38 | })
39 | mongoose.connection.on('open', () => {
40 | console.log(`MongoDB is connected at ${endpoint}`)
41 | })
42 |
43 | app.use(compress())
44 | .options('*', cors())
45 | .use(cors())
46 | .use('/', serveStatic(app.get('public')))
47 | .use(bodyParser.json())
48 | .use(bodyParser.urlencoded({extended: true}))
49 | .configure(hooks())
50 | .configure(rest())
51 | .configure(socketio())
52 | .configure(service)
53 | .configure(middleware)
54 |
55 | // This ADMIN user is for new development, update with strong credential or remove it in production
56 | app.service('users').create({
57 | email: 'mo@po.da',
58 | password: 'do',
59 | roles: ['ADMIN']
60 | })
61 |
62 | export default app
63 |
--------------------------------------------------------------------------------
/app/config/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "host": "famn",
3 | "port": 3030,
4 | "mongodb": {
5 | "server": {
6 | "host": "mongo",
7 | "port": 27017
8 | },
9 | "db": "famn"
10 | },
11 | "public": "../../dist/client",
12 | "auth": {
13 | // node -e "console.log(require('crypto').randomBytes(64).toString('hex')"
14 | "secret": "ZJApt91sS3bPV275hfobvCTSJYEgv+1n09A8D4bGlqI9S+lq3oePV1Xwla52ZipAXgaj8X/t17/3Tl6UFi1cOQ==",
15 | "cookie": {
16 | "name": "famn-jwt"
17 | },
18 | "jwt": {
19 | "audience": "https://yourdomain.com",
20 | "issuer": "famn",
21 | "expiresIn": "1d"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/config/production.json:
--------------------------------------------------------------------------------
1 | {
2 | "port": 8080,
3 | "auth": {
4 | "jwt": {
5 | // Make sure you change this secret for production
6 | "secret": "FAMN_AUTH_SECRET"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/hooks/index.ts:
--------------------------------------------------------------------------------
1 | // Add any common hooks you want to share across services in here.
2 | //
3 | // Below is an example of how a hook is written and exported. Please
4 | // see http://docs.feathersjs.com/hooks/readme.html for more details
5 | // on hooks.
6 |
7 | export function myHook(options) {
8 | return hook => {
9 | console.log('My custom global hook ran. Feathers is awesome!')
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/middleware/index.ts:
--------------------------------------------------------------------------------
1 | const handler = require('feathers-errors/handler')
2 | import notFound from './not-found-handler'
3 | import logger from './logger'
4 |
5 | export default function () {
6 | // Add your custom middleware here. Remember, that
7 | // just like Express the order matters, so error
8 | // handling middleware should go last.
9 | const app = this
10 |
11 | app.use(notFound())
12 | app.use(logger(app))
13 | app.use(handler())
14 | }
15 |
--------------------------------------------------------------------------------
/app/middleware/logger.ts:
--------------------------------------------------------------------------------
1 | import * as bunyan from 'bunyan'
2 |
3 | const logger = bunyan.createLogger({ name: 'famn' })
4 |
5 | export default (app) => {
6 | // Add a logger to our app object for convenience
7 | app.logger = logger
8 |
9 | return (error, req, res, next) => {
10 | if (error) {
11 | const message = `${error.code ? `(${error.code}) ` : ''}Route: ${req.url} - ${error.message}`
12 |
13 | if (error.code === 404) {
14 | logger.info(message)
15 | } else {
16 | logger.error(message)
17 | logger.info(error.stack)
18 | }
19 | }
20 | next(error)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/middleware/not-found-handler.ts:
--------------------------------------------------------------------------------
1 | const errors = require('feathers-errors')
2 |
3 | export default () => {
4 | return (req, res, next) => {
5 | next(new errors.NotFound('Page not found'))
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/app/middleware/webpack-hot.ts:
--------------------------------------------------------------------------------
1 | import * as webpack from 'webpack'
2 | import webpackConfig from '../../client/config/webpack.dev'
3 | const compiler = webpack(webpackConfig)
4 |
5 |
6 | export default function () {
7 | const app = this
8 |
9 | app.use(require('webpack-dev-middleware')(compiler, {
10 | noInfo: true,
11 | publicPath: webpackConfig.output.publicPath
12 | }))
13 |
14 | app.use(require('webpack-hot-middleware')(compiler))
15 | }
16 |
--------------------------------------------------------------------------------
/app/models/message.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose'
2 |
3 | const messageSchema = new mongoose.Schema({
4 | email: {
5 | type: String,
6 | required: true
7 | },
8 | message: {
9 | type: String,
10 | default: ''
11 | }
12 | },
13 | { timestamps: {} })
14 |
15 | export default mongoose.model('Message', messageSchema)
16 |
--------------------------------------------------------------------------------
/app/models/user.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose'
2 |
3 | const userSchema = new mongoose.Schema({
4 | email: {
5 | type: String,
6 | required: true,
7 | unique: true
8 | },
9 | password: {
10 | type: String,
11 | required: true
12 | },
13 | roles: {
14 | type: [String],
15 | default: []
16 | }
17 | }, {
18 | timestamps: {
19 | createdAt: 'created_at',
20 | updatedAt: 'updated_at'
21 | }
22 | })
23 |
24 | export default mongoose.model('User', userSchema)
25 |
--------------------------------------------------------------------------------
/app/service/authentication/hooks/index.ts:
--------------------------------------------------------------------------------
1 | const auth = require('feathers-authentication')
2 |
3 | const before = {
4 | create: [
5 | auth.hooks.authenticate(['jwt', 'local'])
6 | ],
7 | remove: [
8 | auth.hooks.authenticate('jwt')
9 | ]
10 | }
11 |
12 | export default {
13 | before
14 | }
15 |
--------------------------------------------------------------------------------
/app/service/authentication/index.ts:
--------------------------------------------------------------------------------
1 | const authentication = require('feathers-authentication')
2 | const jwt = require('feathers-authentication-jwt')
3 | const local = require('feathers-authentication-local')
4 | import hooks from './hooks'
5 |
6 |
7 |
8 | export default function() {
9 | const app = this
10 |
11 | let config = app.get('auth')
12 |
13 | app.configure(authentication(config))
14 | .configure(jwt())
15 | .configure(local())
16 |
17 | app.service('authentication').before(hooks.before)
18 | }
19 |
--------------------------------------------------------------------------------
/app/service/index.ts:
--------------------------------------------------------------------------------
1 | import authentication from './authentication'
2 | import user from './user'
3 | import message from './message'
4 |
5 | export default function () {
6 | const app = this
7 |
8 | app.configure(authentication)
9 | .configure(user)
10 | .configure(message)
11 | }
12 |
--------------------------------------------------------------------------------
/app/service/message/hooks/index.ts:
--------------------------------------------------------------------------------
1 | import * as globalHooks from '../../../hooks'
2 | // const auth = require('feathers-authentication')
3 |
4 |
5 |
6 |
7 | const before = {
8 | all: [
9 | // auth.hooks.authenticate('jwt')
10 | ],
11 | find: [],
12 | get: [],
13 | create: [],
14 | update: [],
15 | patch: [],
16 | remove: []
17 | }
18 |
19 | const after = {
20 | all: [],
21 | find: [],
22 | get: [],
23 | create: [],
24 | update: [],
25 | patch: [],
26 | remove: []
27 | }
28 |
29 | export default {
30 | before,
31 | after
32 | }
33 |
--------------------------------------------------------------------------------
/app/service/message/index.ts:
--------------------------------------------------------------------------------
1 | const service = require('feathers-mongoose')
2 | import hooks from './hooks'
3 | import MessageModel from '../../models/message'
4 |
5 | export default function() {
6 | const app = this
7 |
8 | let options = {
9 | Model: MessageModel,
10 | paginate: {
11 | default: 100,
12 | max: 200
13 | }
14 | }
15 |
16 | app.use('/messages', service(options))
17 | const messageService = app.service('messages')
18 | messageService.before(hooks.before)
19 | messageService.after(hooks.after)
20 | }
21 |
--------------------------------------------------------------------------------
/app/service/user/hooks/index.ts:
--------------------------------------------------------------------------------
1 | import * as globalHooks from '../../../hooks'
2 | const hooks = require('feathers-hooks')
3 | const auth = require('feathers-authentication')
4 | const local = require('feathers-authentication-local')
5 | const permissions = require('feathers-permissions')
6 |
7 | const adminPermission = permissions.hooks.checkPermissions({
8 | roles: ['ADMIN'],
9 | on: 'user',
10 | field: 'roles'
11 | })
12 |
13 | const before = {
14 | all: [
15 | ],
16 | find: [
17 | adminPermission,
18 | permissions.hooks.isPermitted(),
19 | auth.hooks.authenticate('jwt')
20 | ],
21 | get: [
22 | auth.hooks.authenticate('jwt')
23 | ],
24 | create: [
25 | adminPermission,
26 | permissions.hooks.isPermitted(),
27 | local.hooks.hashPassword()
28 | ],
29 | update: [
30 | auth.hooks.authenticate('jwt'),
31 | local.hooks.hashPassword()
32 | ],
33 | patch: [
34 | auth.hooks.authenticate('jwt'),
35 | local.hooks.hashPassword()
36 | ],
37 | remove: [
38 | adminPermission,
39 | permissions.hooks.isPermitted(),
40 | auth.hooks.authenticate('jwt'),
41 | ]
42 | }
43 |
44 | const after = {
45 | all: [hooks.remove('password')],
46 | find: [],
47 | get: [],
48 | create: [],
49 | update: [],
50 | patch: [],
51 | remove: []
52 | }
53 |
54 | export default {
55 | before,
56 | after
57 | }
58 |
--------------------------------------------------------------------------------
/app/service/user/index.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path'
2 | import * as mongoose from 'mongoose'
3 | const service = require('feathers-mongoose')
4 | import UserModel from '../../models/user'
5 | import hooks from './hooks'
6 |
7 |
8 |
9 | export default function() {
10 | const app = this
11 |
12 | let options = {
13 | Model: UserModel,
14 | paginate: {
15 | default: 25,
16 | max: 25
17 | }
18 | }
19 |
20 | // Initialize 'users' service
21 | app.use('/users', service(options))
22 |
23 | // Get 'users' service to build hooks
24 | const userService = app.service('users')
25 |
26 | // Set up our before hooks
27 | userService.before(hooks.before)
28 |
29 | // Set up our after hooks
30 | userService.after(hooks.after)
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/app/webpack/webpack.server.common.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @author: hjl
3 | */
4 |
5 | const webpack = require('webpack')
6 | import { helpers } from '../../client/config/helpers'
7 |
8 | /*
9 | * Webpack Plugins
10 | */
11 | const ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin
12 | const DefinePlugin = require('webpack/lib/DefinePlugin')
13 |
14 |
15 |
16 | /*
17 | * Webpack Constants
18 | */
19 | const ENV = process.env.ENV = process.env.NODE_ENV = 'production'
20 | const METADATA = {
21 | ENV: ENV,
22 | title: 'Implus Admin Seed - server',
23 | // baseUrl: '/'
24 | }
25 |
26 | const fs = require('fs')
27 | // Look here http://jlongster.com/Backend-Apps-with-Webpack--Part-I
28 | const nodeModules = {}
29 | fs.readdirSync('node_modules')
30 | .filter(x => ['.bin'].indexOf(x) === -1)
31 | .forEach(mod => nodeModules[mod] = 'commonjs ' + mod)
32 |
33 | /*
34 | * Webpack configuration
35 | *
36 | * See: http://webpack.github.io/docs/configuration.html#cli
37 | */
38 | export default {
39 | target: 'node',
40 |
41 | /*
42 | * The entry point for the bundle
43 | * Our Angular.js app
44 | *
45 | * See: http://webpack.github.io/docs/configuration.html#entry
46 | */
47 | entry: './server.ts',
48 |
49 | output: {
50 | path: helpers.root('dist/server'),
51 | filename: 'server.bundle.js'
52 | },
53 |
54 | devtool: 'eval',
55 | externals: nodeModules,
56 |
57 |
58 | /*
59 | * Options affecting the resolving of modules.
60 | *
61 | * See: http://webpack.github.io/docs/configuration.html#resolve
62 | */
63 | resolve: {
64 |
65 | /*
66 | * An array of extensions that should be used to resolve modules.
67 | *
68 | * See: http://webpack.github.io/docs/configuration.html#resolve-extensions
69 | */
70 | extensions: ['.ts', '.js', '.json'],
71 | modules: [helpers.root('app'), helpers.root('node_modules')],
72 | },
73 |
74 | /*
75 | * Options affecting the normal modules.
76 | *
77 | * See: http://webpack.github.io/docs/configuration.html#module
78 | */
79 | module: {
80 | /*
81 | * An array of automatically applied loaders.
82 | *
83 | * IMPORTANT: The loaders here are resolved relative to the resource which they are applied to.
84 | * This means they are not resolved relative to the configuration file.
85 | *
86 | * See: http://webpack.github.io/docs/configuration.html#module-loaders
87 | */
88 | rules: [
89 | {
90 | test: /\.ts$/,
91 | use: [
92 | {
93 | loader: 'awesome-typescript-loader',
94 | options: {
95 | configFileName: 'tsconfig.server.json'
96 | }
97 | },
98 | ],
99 | exclude: [/node_modules/]
100 | },
101 |
102 | /*
103 | * Json loader support for *.json files.
104 | *
105 | * See: https://github.com/webpack/json-loader
106 | */
107 | {
108 | test: /\.json$/,
109 | use: 'json-loader'
110 | },
111 | ]
112 |
113 | },
114 |
115 | /*
116 | * Include polyfills or mocks for various node stuff
117 | * Description: Node configuration
118 | *
119 | * See: https://webpack.github.io/docs/configuration.html#node
120 | */
121 | node: {
122 | global: true,
123 | crypto: 'empty',
124 | process: true,
125 | module: false,
126 | clearImmediate: false,
127 | setImmediate: false
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/client/app/404/404.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Error 404
6 |
7 |
10 | Oops! You lost your way
11 |
12 |
13 |
--------------------------------------------------------------------------------
/client/app/404/404.component.scss:
--------------------------------------------------------------------------------
1 | .page-not-found {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | right: 0;
6 | bottom: 0;
7 | padding: 50px;
8 |
9 | md-card {
10 | width: 500px;
11 | padding: 0;
12 | }
13 |
14 | md-toolbar {
15 | padding: 50px 80px;
16 | height: 200px;
17 | h1 {
18 | font-weight: lighter;
19 | }
20 | }
21 |
22 | button[md-fab] {
23 | left: 80%;
24 | top: -28px
25 | }
26 |
27 | md-card-title {
28 | padding: 16px;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/client/app/404/404.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import { Router } from '@angular/router'
3 |
4 | @Component({
5 | selector: 'page-not-found',
6 | templateUrl: './404.component.html',
7 | styleUrls: ['./404.component.scss']
8 | })
9 |
10 | export class PageNotFoundComponent {
11 | constructor(private _router: Router) { }
12 | gotoHome() {
13 | this._router.navigate(['/module', 'home'])
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/client/app/app.component.scss:
--------------------------------------------------------------------------------
1 | famn-app {
2 | position: absolute;
3 | // margin: 0;
4 | // width: 100%;
5 | // height: 100%;
6 | top: 0px;
7 | left: 0px;
8 | right: 0px;
9 | bottom: 0px;
10 | background-color: whitesmoke;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/client/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation } from '@angular/core'
2 |
3 | // import { AppStore } from './app.store'
4 | @Component({
5 | selector: 'famn-app',
6 | templateUrl: 'app.component.html',
7 | styleUrls: ['./app.component.scss'],
8 | encapsulation: ViewEncapsulation.None
9 | })
10 | export class AppComponent {
11 | // constructor(public appStore: AppStore) {
12 | public _isDev: boolean = ENV === 'development' ? true : false
13 | constructor() {
14 | console.log('welcome to FAMN')
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/app/app.global.scss:
--------------------------------------------------------------------------------
1 | @import "./shared/material";
2 |
3 |
4 |
5 | html, body{
6 | height: 100%;
7 | width: 100%;
8 | margin: 0;
9 | font-family: Roboto, "Helvetica Neue", sans-serif;
10 | }
11 |
12 | h1, h2, h3, h4, h5, h6 {
13 | margin: 0px;
14 | }
15 |
16 | [md-fab].fixed-bottom-right {
17 | position: fixed;
18 | right: 60px;
19 | bottom: 100px;
20 | }
21 |
--------------------------------------------------------------------------------
/client/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ApplicationRef } from '@angular/core'
2 | import { BrowserModule } from '@angular/platform-browser'
3 | import { CommonModule } from '@angular/common'
4 | import { FormsModule } from '@angular/forms'
5 | import { HttpModule } from '@angular/http'
6 | import { RouterModule } from '@angular/router'
7 | import { removeNgStyles, createNewHosts, createInputTransfer } from '@angularclass/hmr'
8 |
9 | import './app.global.scss'
10 |
11 | /**
12 | * Import ngrx
13 | */
14 | import { compose } from '@ngrx/core/compose'
15 | import { Store, StoreModule, ActionReducer, combineReducers } from '@ngrx/store'
16 | import { StoreDevtoolsModule } from '@ngrx/store-devtools'
17 | import { StoreLogMonitorModule, useLogMonitor } from '@ngrx/store-log-monitor'
18 |
19 | import { MaterialModule } from '@angular/material'
20 | import { FlexLayoutModule } from '@angular/flex-layout'
21 |
22 | /**
23 | * Import toplevel component/providers/directives/pipes
24 | */
25 | import { AppComponent } from './app.component'
26 | import { LoginComponent } from './login/login.component'
27 | import { SignupComponent } from './signup/signup.component'
28 | import { PageNotFoundComponent } from './404/404.component'
29 | import { SocketService, AuthGuard } from './app.service'
30 | import { ROUTES } from './app.routes'
31 | import { ENV_PROVIDERS } from './env'
32 |
33 |
34 |
35 | /**
36 | * Reducer for @ngrx/store
37 | */
38 | import { message } from '../reducer'
39 |
40 | // Reset the root state for HMR
41 | function stateSetter(reducer: ActionReducer): ActionReducer {
42 | return function (state, action) {
43 | if (action.type === 'SET_ROOT_STATE') {
44 | return action.payload
45 | }
46 | return reducer(state, action)
47 | }
48 | }
49 |
50 | const rootReducer = compose(stateSetter, combineReducers)({
51 | message
52 | })
53 |
54 | let imports = [
55 | BrowserModule,
56 | FormsModule,
57 | HttpModule,
58 | CommonModule,
59 | MaterialModule.forRoot(),
60 | FlexLayoutModule.forRoot(),
61 | RouterModule.forRoot(ROUTES, {
62 | useHash: true
63 | }),
64 |
65 | // StoreLogMonitorModule,
66 | StoreModule.provideStore(rootReducer)
67 | ]
68 |
69 | // Enable HMR and ngrx/devtools in hot reload mode
70 | if (process.env.NODE_ENV === 'development') imports.push(...[
71 | StoreDevtoolsModule.instrumentStore({
72 | monitor: useLogMonitor({
73 | visible: false,
74 | position: 'right'
75 | })
76 | }),
77 | StoreLogMonitorModule,
78 | ])
79 |
80 | @NgModule({
81 | bootstrap: [
82 | AppComponent
83 | ],
84 | declarations: [
85 | AppComponent,
86 | LoginComponent,
87 | SignupComponent,
88 | PageNotFoundComponent
89 | ],
90 | imports,
91 | providers: [
92 | ENV_PROVIDERS,
93 | SocketService,
94 | AuthGuard
95 | ]
96 | })
97 |
98 | export class AppModule {
99 | constructor(public appRef: ApplicationRef, private _store: Store) { }
100 | hmrOnInit(store) {
101 | if (!store || !store.rootState) return
102 |
103 | // restore state
104 | if (store.rootState) {
105 | this._store.dispatch({
106 | type: 'SET_ROOT_STATE',
107 | payload: store.rootState
108 | })
109 | }
110 |
111 | // restore input values
112 | if ('restoreInputValues' in store) { store.restoreInputValues() }
113 | this.appRef.tick()
114 | Object.keys(store).forEach(prop => delete store[prop])
115 | }
116 | hmrOnDestroy(store) {
117 | const cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement)
118 | this._store.subscribe(s => store.rootState = s)
119 | // recreate elements
120 | store.disposeOldHosts = createNewHosts(cmpLocation)
121 | // save input values
122 | store.restoreInputValues = createInputTransfer()
123 | // remove styles
124 | removeNgStyles()
125 | }
126 | hmrAfterDestroy(store) {
127 | // display new elements
128 | store.disposeOldHosts()
129 | delete store.disposeOldHosts
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/client/app/app.routes.ts:
--------------------------------------------------------------------------------
1 | import { LoginComponent } from './login/login.component'
2 | import { SignupComponent } from './signup/signup.component'
3 | import { PageNotFoundComponent } from './404/404.component'
4 | import { ModModule } from './module'
5 | import { AuthGuard } from './app.service'
6 |
7 |
8 | function loadModModule() {
9 | return ModModule
10 | }
11 |
12 | export const ROUTES = [
13 | {
14 | path: '',
15 | redirectTo: '/login',
16 | pathMatch: 'full'
17 | },
18 | {
19 | path: 'login',
20 | component: LoginComponent
21 | },
22 | {
23 | path: 'signup',
24 | component: SignupComponent
25 | },
26 | {
27 | path: 'module',
28 | loadChildren: loadModModule,
29 | canActivate: [AuthGuard]
30 | },
31 | {
32 | path: '404-page',
33 | component: PageNotFoundComponent,
34 | },
35 | { path: '**', redirectTo: '/404-page' }
36 | ]
37 |
--------------------------------------------------------------------------------
/client/app/app.service.ts:
--------------------------------------------------------------------------------
1 | import * as feathers from 'feathers/client'
2 | import * as socketio from 'feathers-socketio/client'
3 | const io = require('socket.io-client')
4 | const hooks = require('feathers-hooks')
5 | import * as authentication from 'feathers-authentication-client'
6 |
7 | import RxJS from 'rxjs'
8 |
9 | import { Injectable } from '@angular/core'
10 | import { Router, CanActivate } from '@angular/router'
11 | import { helpers } from '../config/helpers'
12 |
13 | @Injectable()
14 | export class SocketService {
15 | public socket: any
16 | public app: any
17 |
18 | constructor() {
19 | this.socket = io(helpers.getHost())
20 | this.app = feathers()
21 | .configure(socketio(this.socket))
22 | .configure(hooks())
23 | .configure(authentication({
24 | cookie: 'famn-jwt',
25 | storageKey: 'famn-jwt',
26 | storage: window.localStorage
27 | }))
28 | }
29 |
30 | getService(service) {
31 | return this.app.service(service)
32 | }
33 |
34 | authenticate(option?: any) {
35 | return this.app.authenticate(option)
36 | }
37 |
38 | logout() {
39 | // feathers-authentication-client will bind logout method to app
40 | // app.logout = app.passport.logout.bind(app.passport);
41 | return this.app.logout()
42 | }
43 |
44 | getUser() {
45 | return this.app.get('user')
46 | }
47 |
48 | getToken() {
49 | return this.app.get('token')
50 | }
51 |
52 | isLogin() {
53 | return this.getUser() ? true : false
54 | }
55 | }
56 |
57 |
58 |
59 | @Injectable()
60 | /**
61 | * AuthGuard service is to provide client side router authorization
62 | */
63 | export class AuthGuard implements CanActivate {
64 | constructor(private _socketService: SocketService, private _router: Router) { }
65 |
66 | canActivate() {
67 | // if (this._socketService.isLogin()) return true
68 | // this._router.navigate(['/'])
69 | // return false
70 | return this._socketService.isLogin() || this._socketService.authenticate()
71 | .then(res => this._socketService.app.passport.verifyJWT(res.accessToken))
72 | .then(payload => this._socketService.app.service('users').get(payload.userId))
73 | .then(user => this._socketService.app.set('user', user))
74 | .then(res => true)
75 | .catch(err => {
76 | this._router.navigate(['/login']
77 | )
78 | })
79 | }
80 | }
81 |
82 |
--------------------------------------------------------------------------------
/client/app/env.ts:
--------------------------------------------------------------------------------
1 |
2 | // Angular 2
3 | // rc2 workaround
4 | import { enableDebugTools, disableDebugTools } from '@angular/platform-browser'
5 | import { enableProdMode, ApplicationRef } from '@angular/core'
6 | // Environment Providers
7 | let PROVIDERS: any[] = [
8 | // common env directives
9 | ];
10 |
11 | // Angular debug tools in the dev console
12 | // https://github.com/angular/angular/blob/86405345b781a9dc2438c0fbe3e9409245647019/TOOLS_JS.md
13 | let _decorateModuleRef = function identity(value: T): T { return value; }
14 |
15 | if ('production' === ENV) {
16 | // Production
17 | disableDebugTools()
18 | enableProdMode()
19 |
20 | PROVIDERS = [
21 | ...PROVIDERS,
22 | // custom providers in production
23 | ]
24 |
25 | } else {
26 |
27 | _decorateModuleRef = (modRef: any) => {
28 | const appRef = modRef.injector.get(ApplicationRef)
29 | const cmpRef = appRef.components[0]
30 |
31 | let _ng = (window).ng
32 | enableDebugTools(cmpRef);
33 | (window).ng.probe = _ng.probe;
34 | (window).ng.coreTokens = _ng.coreTokens
35 | return modRef
36 | }
37 |
38 | // Development
39 | PROVIDERS = [
40 | ...PROVIDERS,
41 | // custom providers in development
42 | ]
43 |
44 | }
45 |
46 | export const decorateModuleRef = _decorateModuleRef
47 |
48 | export const ENV_PROVIDERS = [
49 | ...PROVIDERS
50 | ]
51 |
--------------------------------------------------------------------------------
/client/app/index.ts:
--------------------------------------------------------------------------------
1 | // import global style
2 | import './app.global.scss'
3 |
4 | export * from './app.module'
5 |
--------------------------------------------------------------------------------
/client/app/login/login.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | FAMN
4 |
5 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/client/app/login/login.component.scss:
--------------------------------------------------------------------------------
1 | .login {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | right: 0;
6 | bottom: 0;
7 | padding: 50px;
8 |
9 | md-card {
10 | padding: 0;
11 | }
12 |
13 | md-card-content {
14 | padding: 16px;
15 |
16 | md-button:hover {
17 | background-color: transparent;
18 | }
19 | }
20 |
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/client/app/login/login.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import { Router } from '@angular/router'
3 | import { LoginService } from './login.service'
4 |
5 | @Component({
6 | selector: 'login-cmp',
7 | providers: [LoginService],
8 | templateUrl: 'login.component.html',
9 | styleUrls: ['./login.component.scss']
10 | })
11 |
12 | export class LoginComponent {
13 | public user: any = {}
14 | public showLogin: boolean = false
15 |
16 | constructor(private _router: Router, private _loginService: LoginService) {}
17 |
18 | ngOnInit() {
19 | this._loginService.loginToken()
20 | .then(res => {
21 | this._router.navigate(['/module'])
22 | })
23 | .catch(err => {
24 | // No token in localStorage, should go local authentication way
25 | this.showLogin = true
26 | })
27 | }
28 |
29 | onSubmit() {
30 | this._loginService.loginLocal(this.user)
31 | .then(res => {
32 | this._router.navigate(['/module'])
33 | })
34 | .catch(err => {
35 | console.log(err)
36 | })
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/client/app/login/login.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core'
2 | import { Observable } from 'rxjs/Observable'
3 | import { SocketService } from '../app.service'
4 |
5 | interface User {
6 | email: String,
7 | password: String
8 | }
9 |
10 | @Injectable()
11 | export class LoginService {
12 | // public resource$: Observable
13 | // private _observable
14 | private _app
15 |
16 | constructor(private _socketService: SocketService) {
17 | this._app = this._socketService.app
18 |
19 |
20 | // this.item$ is a public observable for components to subscribe
21 | // this.resource$ = new Observable(observable => this._observable = observable)
22 | }
23 |
24 |
25 | // authentication from 'local' by email and password
26 | loginLocal(user: User) {
27 | let option = Object.assign({}, { strategy: 'local' }, user)
28 | return this.deriveUser(option)
29 | }
30 |
31 | // authentical from the token in localStorage
32 | loginToken(): any {
33 | return this.deriveUser({})
34 | }
35 |
36 | deriveUser(option: any): any {
37 | return this._socketService.authenticate(option)
38 | .then(res => {
39 | return this._app.passport.verifyJWT(res.accessToken)
40 | })
41 | .then(payload => {
42 | return this._app.service('users').get(payload.userId)
43 | })
44 | .then(user => {
45 | return this._app.set('user', user)
46 | })
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/client/app/meta.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Dashboard",
4 | "id": "dashboard"
5 | },
6 | {
7 | "name": "Message",
8 | "id": "message"
9 | },
10 | {
11 | "name": "User",
12 | "id": "user"
13 | }
14 | ]
15 |
--------------------------------------------------------------------------------
/client/app/module/dashboard/dashboard.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/client/app/module/dashboard/dashboard.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {TodoComponent, StatsComponent} from '../../../widgets'
3 |
4 |
5 | @Component({
6 | selector: 'dashboard-module',
7 | templateUrl: 'dashboard.component.html'
8 | })
9 |
10 | export class DashboardComponent {
11 | constructor() { }
12 |
13 | ngOnInit() {
14 | console.log('This is dashboard module')
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/app/module/dashboard/dashboard.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { CommonModule } from '@angular/common'
3 | import { FormsModule } from '@angular/forms'
4 | import { RouterModule } from '@angular/router'
5 |
6 | /**
7 | * Import @angular/material, ng2-material
8 | */
9 | import { MaterialModule } from '@angular/material'
10 |
11 | import { DashboardComponent } from './dashboard.component'
12 | import { TodoComponent } from '../../widgets/todo'
13 |
14 | import { ROUTES } from './dashboard.routes'
15 |
16 |
17 | @NgModule({
18 | declarations: [
19 | DashboardComponent,
20 | TodoComponent
21 | ],
22 | imports: [
23 | CommonModule,
24 | FormsModule,
25 | MaterialModule.forRoot(),
26 | RouterModule.forChild(ROUTES),
27 | ]
28 | })
29 | export class DashboardModule {
30 | constructor() { }
31 | }
32 |
--------------------------------------------------------------------------------
/client/app/module/dashboard/dashboard.routes.ts:
--------------------------------------------------------------------------------
1 | import { DashboardComponent } from './dashboard.component'
2 |
3 | export const ROUTES = [
4 | {
5 | path: '',
6 | component: DashboardComponent
7 | }
8 | ]
9 |
--------------------------------------------------------------------------------
/client/app/module/dashboard/index.ts:
--------------------------------------------------------------------------------
1 | export * from './dashboard.module'
2 |
--------------------------------------------------------------------------------
/client/app/module/home/home.component.html:
--------------------------------------------------------------------------------
1 | Welcome to FAMN
2 |
--------------------------------------------------------------------------------
/client/app/module/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 |
3 | @Component({
4 | selector: 'home-module',
5 | templateUrl: './home.component.html',
6 | })
7 |
8 | export class HomeComponent {
9 | constructor() { }
10 | }
11 |
--------------------------------------------------------------------------------
/client/app/module/index.ts:
--------------------------------------------------------------------------------
1 | export { ModModule } from './mod.module'
2 |
--------------------------------------------------------------------------------
/client/app/module/message/index.ts:
--------------------------------------------------------------------------------
1 | export * from './message.module'
2 |
--------------------------------------------------------------------------------
/client/app/module/message/message.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Messages
4 |
5 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/client/app/module/message/message.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, OnDestroy } from '@angular/core'
2 | import { MessageService } from './message.service'
3 |
4 | import { Store } from '@ngrx/store'
5 | import { Observable } from 'rxjs/Observable'
6 |
7 | import { GridOptions } from 'ag-grid/main'
8 |
9 | @Component({
10 | selector: 'message',
11 | templateUrl: 'message.component.html',
12 | providers: [MessageService]
13 | })
14 |
15 | export class MessageComponent implements OnInit, OnDestroy {
16 | private message$: Observable
17 | private messageSubscription: any
18 | public gridOptions: GridOptions
19 | public columnDefs: any[]
20 | public messages = []
21 | public email: string
22 | public message: string
23 |
24 | constructor(private _store: Store,
25 | private messageService: MessageService) {
26 |
27 | this.message$ = this._store.select('message')
28 |
29 | this.messageSubscription = this.message$.subscribe((messages: any[]) => {
30 | this.messages = messages
31 | this.createDataSource()
32 | })
33 |
34 | this.messageService.resource$.subscribe(res => {
35 | switch (res.type) {
36 | case 'find':
37 | this._store.dispatch({
38 | type: 'MESSAGE_INIT',
39 | payload: res.messages
40 | })
41 | break
42 | case 'created':
43 | // this._store.dispatch({
44 | // type: 'MESSAGE_UPDATE',
45 | // payload: res.messages
46 | // })
47 | this.messageService.findMessages()
48 | break
49 | default:
50 | break
51 | }
52 | })
53 |
54 | // ag-grid initialization
55 | this.gridOptions = {}
56 | this.columnDefs = this.createColumnDefs()
57 | this.email = 'anonymous'
58 | this.message = ''
59 | }
60 |
61 |
62 | ngOnInit() {
63 | }
64 |
65 | ngOnDestroy() {
66 | this.messageSubscription.unsubscribe()
67 | this.messageService.off()
68 | }
69 |
70 | onGridReady() {
71 | this.gridOptions.api.sizeColumnsToFit()
72 | this.messageService.findMessages()
73 | }
74 |
75 | createColumnDefs() {
76 | return [
77 | {
78 | headerName: 'Email',
79 | field: 'email'
80 | },
81 | {
82 | headerName: 'Message',
83 | field: 'message'
84 | },
85 | {
86 | headerName: 'Created Time',
87 | field: 'createdAt'
88 | },
89 | {
90 | headerName: 'Updated Time',
91 | field: 'updatedAt'
92 | }
93 | ]
94 | }
95 |
96 |
97 | createDataSource() {
98 | if (!this.gridOptions) return
99 | let dataSource = {
100 | rowCount: -1,
101 | getRows: params => {
102 | let rowsThisPage = this.messages.slice(params.startRow, params.endRow)
103 | let lastRow = -1
104 | if (this.messages.length <= params.endRow) {
105 | lastRow = this.messages.length
106 | }
107 | params.successCallback(rowsThisPage, this.messages.length)
108 | }
109 | }
110 |
111 | this.gridOptions.api.setDatasource(dataSource)
112 | }
113 |
114 | createMessage() {
115 | this.messageService.createMessage({
116 | email: this.email,
117 | message: this.message
118 | })
119 |
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/client/app/module/message/message.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { CommonModule } from '@angular/common'
3 | import { FormsModule } from '@angular/forms'
4 | import { RouterModule } from '@angular/router'
5 |
6 | import { MaterialModule } from '@angular/material'
7 | import { FlexLayoutModule } from '@angular/flex-layout'
8 |
9 |
10 | import {AgGridModule} from 'ag-grid-angular/main'
11 | import 'ag-grid/dist/styles/ag-grid.css'
12 | import 'ag-grid/dist/styles/theme-material.css'
13 |
14 |
15 | import { MessageComponent } from './message.component'
16 |
17 | import { ROUTES } from './message.routes'
18 |
19 | @NgModule({
20 | declarations: [
21 | MessageComponent,
22 | ],
23 | imports: [
24 | CommonModule,
25 | FormsModule,
26 | MaterialModule.forRoot(),
27 | FlexLayoutModule.forRoot(),
28 | AgGridModule.withComponents([]),
29 | RouterModule.forChild(ROUTES),
30 | ]
31 | })
32 | export class MessageModule {
33 | constructor() { }
34 | }
35 |
--------------------------------------------------------------------------------
/client/app/module/message/message.routes.ts:
--------------------------------------------------------------------------------
1 | import { MessageComponent } from './message.component'
2 |
3 | export const ROUTES = [
4 | {
5 | path: '',
6 | component: MessageComponent
7 | }
8 | ]
9 |
--------------------------------------------------------------------------------
/client/app/module/message/message.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core'
2 | import { Response } from '@angular/http'
3 | import { Observable } from 'rxjs/Observable'
4 | import { SocketService } from '../../app.service'
5 | import 'rxjs/add/observable/fromPromise'
6 |
7 |
8 | @Injectable()
9 | export class MessageService {
10 | public resource$: Observable
11 | private _observable
12 | private socketMessagesService
13 |
14 | constructor(private _socketService: SocketService) {
15 | this.socketMessagesService = _socketService.getService('messages')
16 |
17 | // this.item$ is a public observable for components to subscribe
18 | this.resource$ = new Observable(observable => this._observable = observable)
19 |
20 | this.socketMessagesService.on('created', res => {
21 | this._observable.next({
22 | type: 'created',
23 | messages: res
24 | })
25 | })
26 |
27 | }
28 |
29 | findMessages() {
30 | this.socketMessagesService.find({
31 | query: {
32 | $sort: {createdAt: -1}
33 | }
34 | }).then(res => {
35 | this._observable.next({
36 | type: 'find',
37 | messages: res.data
38 | })
39 | })
40 | }
41 |
42 | createMessage(data) {
43 | Observable.fromPromise(this.socketMessagesService.create(data))
44 | .catch(this.handleError)
45 | }
46 |
47 |
48 | handleError(err: Response | any) {
49 | err = err instanceof Response ? err.json() : err.toString()
50 | console.error(err)
51 | return Observable.throw(err)
52 | }
53 |
54 | off() {
55 | this.socketMessagesService.removeAllListeners('created')
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/client/app/module/mod.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ApplicationRef } from '@angular/core'
2 | import { CommonModule } from '@angular/common'
3 | import { HttpModule } from '@angular/http'
4 | import { RouterModule } from '@angular/router'
5 |
6 | import { MaterialModule } from '@angular/material'
7 | import { FlexLayoutModule } from '@angular/flex-layout'
8 |
9 |
10 |
11 | /**
12 | * Import toplevel component/providers/directives/pipes
13 | */
14 | import { ModComponent } from './module.component'
15 | import { FooterComponent } from '../shared/footer/footer.component'
16 | import { HomeComponent } from './home/home.component'
17 |
18 | import { ModuleService, NavigationService, VersionService } from '../shared/index'
19 | import { ROUTES } from './module.routes'
20 |
21 | const APP_PROVIDERS = [
22 | ModuleService,
23 | NavigationService,
24 | VersionService,
25 | ]
26 |
27 | @NgModule({
28 | declarations: [
29 | ModComponent,
30 | FooterComponent,
31 | HomeComponent,
32 | ],
33 | imports: [
34 | HttpModule,
35 | CommonModule,
36 | MaterialModule.forRoot(),
37 | FlexLayoutModule.forRoot(),
38 | RouterModule.forChild(ROUTES),
39 | ],
40 | providers: [
41 | ...APP_PROVIDERS,
42 | // SocketService,
43 | // AuthGuard
44 | ]
45 | })
46 |
47 | export class ModModule {
48 | constructor() { }
49 | }
50 |
--------------------------------------------------------------------------------
/client/app/module/module.component.html:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
21 |
22 | Modules –
23 | {{navigation?.currentTitle}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/client/app/module/module.component.scss:
--------------------------------------------------------------------------------
1 | md-sidenav-container,
2 | .app-content {
3 | position: relative;
4 | margin: 0;
5 | width: 100%;
6 | height: 100%;
7 |
8 | .username {
9 | color: #fff;
10 | font-size: 14px;
11 | font-weight: normal;
12 | }
13 | }
14 |
15 | md-sidenav {
16 | width: 200px;
17 | box-shadow: 3px 0 6px rgba(0,0,0,.24);
18 |
19 | .menu-button {
20 | text-align: left;
21 | }
22 | }
23 |
24 |
25 | .app-content-inner {
26 | position: absolute;
27 | top: 64px;
28 | left: 0;
29 | right: 0;
30 | bottom: 0;
31 | overflow: auto;
32 |
33 | .app-content-main {
34 | padding: 30px;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/client/app/module/module.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Component,
3 | OnInit,
4 | OnDestroy,
5 | AfterViewInit,
6 | ViewChild,
7 | Input,
8 | ChangeDetectorRef,
9 | Renderer,
10 | ElementRef,
11 | } from '@angular/core'
12 | import { Router } from '@angular/router'
13 |
14 | import { MdSidenav } from '@angular/material'
15 | import { ModuleMeta, ModuleService } from '../shared/module.service'
16 | import { SocketService } from '../app.service'
17 | import { Http, Response } from '@angular/http'
18 | import { NavigationService } from '../shared/navigation.service'
19 | import { Subscription } from 'rxjs/Subscription'
20 | import { Observable } from 'rxjs/Rx'
21 |
22 | @Component({
23 | templateUrl: 'module.component.html',
24 | styleUrls: ['./module.component.scss']
25 | // encapsulation: ViewEncapsulation.None
26 | })
27 | export class ModComponent implements OnInit, OnDestroy, AfterViewInit {
28 | static SIDE_MENU_BREAKPOINT: string = 'gt-md'
29 |
30 | site: string = 'FAMN'
31 | version: string
32 | modules: ModuleMeta[] = []
33 |
34 | @ViewChild('menu') private menu: MdSidenav
35 |
36 | private _isDev: boolean = ENV === 'development' ? true : false
37 | private _subscription = null
38 | private user = undefined
39 |
40 |
41 | constructor(private http: Http,
42 | // private changeDetectorRef: ChangeDetectorRef,
43 | private navigation: NavigationService,
44 | // private media: Media,
45 | element: ElementRef,
46 | renderer: Renderer,
47 | private _router: Router,
48 | private _modules: ModuleService,
49 | private _socketService: SocketService) {
50 | // Remove loading class to unset default styles
51 | renderer.setElementClass(element.nativeElement, 'loading', false)
52 | }
53 |
54 | ngOnInit() {
55 | // this.http.get('version.json').subscribe((res: Response) => {
56 | // const json = res.json();
57 | // this.version = json.version;
58 | // this.angularVersion = json['@angular/core'];
59 | // this.linkTag = this.angularVersion.replace(/[>=^~]/g, '');
60 | // });
61 | this._modules.getModules().then((mods) => {
62 | this.modules = mods
63 | let title = 'famn'
64 | document.title = title
65 | this.navigation.currentTitle = title
66 | })
67 |
68 | this.user = this._socketService.getUser()
69 | }
70 |
71 | ngAfterViewInit(): any {
72 | }
73 |
74 | ngOnDestroy(): any {
75 | // this._subscription.unsubscribe()
76 | }
77 |
78 | logout(): void {
79 | this._socketService.logout().then(res => {
80 | this._socketService.app.set('user', null)
81 | this._router.navigate(['/login'])
82 | })
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/client/app/module/module.routes.ts:
--------------------------------------------------------------------------------
1 | import { ModComponent } from './module.component'
2 | import { HomeComponent } from './home/home.component'
3 |
4 | export const ROUTES = [
5 | {
6 | path: '',
7 | component: ModComponent,
8 | children: [
9 | {
10 | path: '',
11 | component: HomeComponent
12 | },
13 | {
14 | path: 'setting',
15 | loadChildren: './setting/setting.module#SettingModule'
16 | },
17 | {
18 | path: 'dashboard',
19 | loadChildren: './dashboard/index#DashboardModule'
20 | },
21 | {
22 | path: 'message',
23 | loadChildren: './message/index#MessageModule'
24 | },
25 | {
26 | path: 'user',
27 | loadChildren: './user/index#UserModule'
28 | }
29 | ]
30 | },
31 | ]
32 |
--------------------------------------------------------------------------------
/client/app/module/setting/password.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/client/app/module/setting/password.component.scss:
--------------------------------------------------------------------------------
1 | @import '~@angular/material/core/theming/theming';
2 | .text-danger {
3 | // color: md-color($md-red, A700);
4 | color: mat-color($mat-pink, A400);
5 | }
6 |
7 | .submit {
8 | margin-top: 10px;
9 | }
10 |
--------------------------------------------------------------------------------
/client/app/module/setting/password.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core'
2 | import { SocketService } from '../../app.service'
3 | import { MdSnackBar } from '@angular/material'
4 |
5 | @Component({
6 | selector: 'setting-password-cmp',
7 | templateUrl: 'password.component.html',
8 | styleUrls: ['./password.component.scss']
9 | })
10 | export class PasswordComponent implements OnInit {
11 | private usersService
12 | public user
13 | public password
14 | public confirmPassword
15 | public isPasswordDiff = false
16 |
17 | constructor(
18 | private socketService: SocketService,
19 | private snackBar: MdSnackBar
20 |
21 | ) {
22 | this.usersService = socketService.getService('users')
23 | this.user = socketService.getUser()
24 | }
25 |
26 | ngOnInit() { }
27 |
28 | onSubmit() {
29 | if (this.password && this.password !== this.confirmPassword) this.isPasswordDiff = true
30 | else {
31 | this.usersService.patch(this.user._id, {
32 | password: this.password
33 | })
34 | .then(res => {
35 | this.snackBar.open('Password has been updated', '', {
36 | duration: 800
37 | })
38 | this.isPasswordDiff = false
39 | this.password = ''
40 | this.confirmPassword = ''
41 | })
42 | .catch(err => {
43 | console.error(err)
44 | })
45 | }
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/client/app/module/setting/profile.component.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/app/module/setting/profile.component.html
--------------------------------------------------------------------------------
/client/app/module/setting/profile.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core'
2 |
3 | @Component({
4 | selector: 'setting-profile-cmp',
5 | templateUrl: 'profile.component.html'
6 | })
7 | export class ProfileComponent implements OnInit {
8 | constructor() { }
9 |
10 | ngOnInit() { }
11 | }
12 |
--------------------------------------------------------------------------------
/client/app/module/setting/setting.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { CommonModule } from '@angular/common'
3 | import { FormsModule } from '@angular/forms'
4 | import { Routes, RouterModule } from '@angular/router'
5 | import { MaterialModule } from '@angular/material'
6 | import { FlexLayoutModule } from '@angular/flex-layout'
7 |
8 |
9 |
10 | import { ProfileComponent } from './profile.component'
11 | import { PasswordComponent } from './password.component'
12 | import { routes } from './setting.routes'
13 |
14 | @NgModule({
15 | imports: [
16 | CommonModule,
17 | FormsModule,
18 | RouterModule.forChild(routes),
19 | MaterialModule.forRoot(),
20 | FlexLayoutModule.forRoot(),
21 | ],
22 | exports: [],
23 | declarations: [
24 | ProfileComponent,
25 | PasswordComponent
26 | ],
27 | providers: [],
28 | })
29 | export class SettingModule { }
30 |
--------------------------------------------------------------------------------
/client/app/module/setting/setting.routes.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { Routes, RouterModule } from '@angular/router'
3 |
4 | import { ProfileComponent } from './profile.component'
5 | import { PasswordComponent } from './password.component'
6 |
7 | export const routes: Routes = [
8 | {
9 | path: '',
10 | children: [
11 | { path: 'profile', component: ProfileComponent },
12 | { path: 'password', component: PasswordComponent },
13 | ]
14 | },
15 | ]
16 |
--------------------------------------------------------------------------------
/client/app/module/user/dialog/addUser.html:
--------------------------------------------------------------------------------
1 | User
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{ r }}
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/client/app/module/user/dialog/addUser.scss:
--------------------------------------------------------------------------------
1 | .full-width {
2 | width: 100%;
3 | }
4 |
--------------------------------------------------------------------------------
/client/app/module/user/index.ts:
--------------------------------------------------------------------------------
1 | export * from './user.module'
2 |
--------------------------------------------------------------------------------
/client/app/module/user/user.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{u.email}}
5 |
6 |
9 |
10 |
13 |
16 |
17 |
18 |
19 | {{r}}
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/client/app/module/user/user.component.scss:
--------------------------------------------------------------------------------
1 | .user-card {
2 | margin: 10px 10px;
3 | }
4 |
--------------------------------------------------------------------------------
/client/app/module/user/user.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core'
2 | import { MdDialog, MdDialogRef } from '@angular/material'
3 |
4 | import { UserService } from './user.service'
5 |
6 | @Component({
7 | selector: 'user',
8 | templateUrl: 'user.component.html',
9 | styleUrls: ['./user.component.scss']
10 | })
11 | export class UserComponent implements OnInit {
12 |
13 | // users: {email: string, password: string, roles: string[]}[] = []
14 | users: any[]
15 |
16 | constructor(
17 | private dialog: MdDialog,
18 | private userService: UserService
19 | ) {
20 | }
21 |
22 | ngOnInit() {
23 | this.findUsers()
24 | }
25 |
26 | findUsers() {
27 | this.userService.findUsers().subscribe(users => {
28 | this.users = users
29 | })
30 | }
31 |
32 | addUser() {
33 | let newUser = {
34 | roles: []
35 | }
36 | this.openUserDialog(newUser, 'new')
37 | .subscribe(user => {
38 | if (!user) return
39 | this.userService.createUser(user)
40 | .subscribe(res => {
41 | console.log('add user', res),
42 | this.findUsers()
43 | })
44 | })
45 | }
46 |
47 |
48 | removeUser(id) {
49 | this.userService.removeUser(id).subscribe(res => {
50 | console.log('remove user', res)
51 | this.findUsers()
52 | })
53 | }
54 |
55 | updateUser(user) {
56 | this.openUserDialog(user, 'update')
57 | .subscribe(user => {
58 | if (!user) return
59 | this.userService.updateUser(user._id, user)
60 | .subscribe(res => {
61 | console.log('update user', res),
62 | this.findUsers()
63 | })
64 | })
65 | }
66 |
67 | openUserDialog(user, mode) {
68 | let dialogRef = this.dialog.open(DialogAddUserComponent, {
69 | width: '500px',
70 | height: '300px'
71 | })
72 | dialogRef.componentInstance.user = JSON.parse(JSON.stringify(user))
73 | dialogRef.componentInstance.mode = mode
74 |
75 | return dialogRef.afterClosed()
76 | }
77 | }
78 |
79 |
80 | @Component({
81 | selector: 'dialog-user',
82 | templateUrl: './dialog/addUser.html',
83 | styleUrls: ['./dialog/addUser.scss']
84 | })
85 | export class DialogAddUserComponent {
86 | user: any
87 | mode: string
88 | roles: string[]
89 |
90 | constructor(public dialogRef: MdDialogRef) {
91 | this.roles = ['ADMIN', 'BUSINESS', 'OPERATION']
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/client/app/module/user/user.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { CommonModule } from '@angular/common'
3 | import { FormsModule } from '@angular/forms'
4 | import { RouterModule } from '@angular/router'
5 |
6 | import { MaterialModule } from '@angular/material'
7 | import { FlexLayoutModule } from '@angular/flex-layout'
8 |
9 |
10 | import { UserComponent, DialogAddUserComponent } from './user.component'
11 | import { UserService } from './user.service'
12 |
13 | import { ROUTES } from './user.routes'
14 |
15 |
16 | @NgModule({
17 | declarations: [
18 | UserComponent,
19 | DialogAddUserComponent,
20 | ],
21 | entryComponents: [
22 | DialogAddUserComponent,
23 | ],
24 | providers: [
25 | UserService
26 | ],
27 | imports: [
28 | CommonModule,
29 | FormsModule,
30 | MaterialModule.forRoot(),
31 | FlexLayoutModule.forRoot(),
32 | RouterModule.forChild(ROUTES),
33 | ],
34 | })
35 | export class UserModule {
36 | constructor() { }
37 | }
38 |
--------------------------------------------------------------------------------
/client/app/module/user/user.routes.ts:
--------------------------------------------------------------------------------
1 | import { UserComponent } from './user.component'
2 |
3 | export const ROUTES = [
4 | {
5 | path: '',
6 | component: UserComponent
7 | }
8 | ]
9 |
--------------------------------------------------------------------------------
/client/app/module/user/user.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core'
2 | import { Response } from '@angular/http'
3 | import { Observable } from 'rxjs/Observable'
4 | import 'rxjs/add/observable/throw'
5 | import 'rxjs/add/observable/fromPromise'
6 |
7 |
8 | import { SocketService } from '../../app.service'
9 |
10 | @Injectable()
11 | export class UserService {
12 | private socketUsersService
13 |
14 | constructor(
15 | private socketService: SocketService
16 | ) {
17 | this.socketUsersService = socketService.getService('users')
18 | }
19 |
20 | findUsers() {
21 | return Observable.fromPromise(this.socketUsersService.find())
22 | .map((res: {data: any[]}) => res.data)
23 | .catch(this.handleError)
24 | }
25 |
26 | createUser(data) {
27 | return Observable.fromPromise(this.socketUsersService.create(data))
28 | .catch(this.handleError)
29 | }
30 |
31 | updateUser(id, data) {
32 | return Observable.fromPromise(this.socketUsersService.update(id, data))
33 | .catch(this.handleError)
34 | }
35 |
36 |
37 | removeUser(id) {
38 | return Observable.fromPromise(this.socketUsersService.remove(id))
39 | .catch(this.handleError)
40 | }
41 |
42 | handleError(err: Response | any) {
43 | err = err instanceof Response ? err.json() : err.toString()
44 | console.error(err)
45 | return Observable.throw(err)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/client/app/shared/footer/footer.component.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/client/app/shared/footer/footer.component.scss:
--------------------------------------------------------------------------------
1 | .footer {
2 | font-size: 16px;
3 | }
4 |
--------------------------------------------------------------------------------
/client/app/shared/footer/footer.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core'
2 | import { NavigationService } from '../navigation.service'
3 |
4 | @Component({
5 | selector: 'footer-cmp',
6 | templateUrl: 'footer.component.html',
7 | styleUrls: ['./footer.component.scss']
8 | })
9 | export class FooterComponent implements OnInit {
10 | constructor(private navigation: NavigationService) { }
11 |
12 | ngOnInit() { }
13 | }
14 |
--------------------------------------------------------------------------------
/client/app/shared/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This barrel file provides the exports for the shared resources (services, components).
3 | */
4 |
5 | // export * from './topnav/index'
6 | // export * from './sidebar/index'
7 | // export * from './+topnav/index'
8 |
9 | export * from './module.service'
10 | export * from './navigation.service'
11 | export * from './version.service'
12 |
--------------------------------------------------------------------------------
/client/app/shared/material.scss:
--------------------------------------------------------------------------------
1 | @import '~@angular/material/core/theming/all-theme';
2 | // Plus imports for other components in your app.
3 |
4 | // Include the base styles for Angular Material core. We include this here so that you only
5 | // have to load a single css file for Angular Material in your app.
6 | @include mat-core();
7 |
8 | // Define the palettes for your theme using the Material Design palettes available in palette.scss
9 | // (imported above). For each palette, you can optionally specify a default, lighter, and darker
10 | // hue.
11 | // $primary: mat-palette($mat-indigo);
12 | // $accent: mat-palette($mat-pink, A200, A100, A400);
13 |
14 | // The warn palette is optional (defaults to red).
15 | // $warn: mat-palette($mat-red);
16 |
17 | // Create the theme object (a Sass map containing all of the palettes).
18 | // $theme: mat-light-theme($primary, $accent, $warn);
19 |
20 | // Include theme styles for core and each component used in your app.
21 | // Alternatively, you can import and @include the theme mixins for each component
22 | // that you are using.
23 | // @include angular-material-theme($theme);
24 |
25 |
26 | $dark-primary: mat-palette($mat-blue-grey);
27 | $dark-accent: mat-palette($mat-amber, A200, A100, A400);
28 | $dark-warn: mat-palette($mat-deep-orange);
29 |
30 | $dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
31 |
32 | @include angular-material-theme($dark-theme);
33 |
--------------------------------------------------------------------------------
/client/app/shared/module.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core'
2 | import { Http, Response } from '@angular/http'
3 |
4 | export interface ModuleMeta {
5 | id: string
6 | readme?: string
7 | name: string
8 | sources: string[]
9 | }
10 |
11 | @Injectable()
12 | export class ModuleService {
13 | public modules: any = null
14 |
15 | private _promise: Promise
16 |
17 | constructor(http: Http) {
18 | this._promise = new Promise((resolve) => {
19 | http.get('meta.json').subscribe((res: Response) => {
20 | this.modules = res.json()
21 | resolve()
22 | })
23 | })
24 | }
25 |
26 | getModules(): Promise {
27 | return this._promise.then(() => this.modules)
28 | }
29 |
30 | getModule(id: string): Promise {
31 | return this._promise.then(() => {
32 | let pick = null
33 | this.modules.forEach((m: ModuleMeta) => {
34 | if (m.id === id) {
35 | pick = m
36 | }
37 | })
38 | return pick
39 | })
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/client/app/shared/navigation.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core'
2 | import { ModuleMeta } from './module.service'
3 |
4 | export interface INavigationLink {
5 | /**
6 | * Brief description of no more than a few words
7 | */
8 | brief: string
9 | /**
10 | * Value to bind to routeLink.
11 | */
12 | routeLink: string
13 | }
14 |
15 | @Injectable()
16 | export class NavigationService {
17 | public currentTitle: string = null
18 | public nextLink: INavigationLink = null
19 | public prevLink: INavigationLink = null
20 |
21 | moduleLink(mod: ModuleMeta): INavigationLink {
22 | return { brief: mod.name, routeLink: '/module/' + mod.id }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/client/app/shared/version.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core'
2 | import { Http, Response } from '@angular/http'
3 |
4 | export interface IVersionMeta {
5 | version: string
6 | readme: string
7 | }
8 |
9 | @Injectable()
10 | export class VersionService {
11 | public meta: IVersionMeta = null
12 |
13 | private _promise: Promise
14 |
15 | constructor(http: Http) {
16 | this._promise = new Promise((resolve) => {
17 | http.get('version.json').subscribe((res: Response) => {
18 | this.meta = res.json()
19 | resolve()
20 | })
21 | })
22 | }
23 |
24 | getMeta(): Promise {
25 | return this._promise.then(() => { return this.meta })
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/app/signup/signup.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | FAMN
4 |
5 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/client/app/signup/signup.component.scss:
--------------------------------------------------------------------------------
1 | .signup {
2 | // position: fixed;
3 | // top: 0;
4 | // left: 0;
5 | // right: 0;
6 | // bottom: 0;
7 | // padding: 50px;
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 |
12 | md-card {
13 | padding: 0;
14 | }
15 |
16 | md-card-content {
17 | padding: 16px;
18 | }
19 |
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/client/app/signup/signup.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import { Router } from '@angular/router'
3 | import { SignupService } from './signup.service'
4 |
5 |
6 | /**
7 | * This class represents the lazy loaded SignupComponent.
8 | */
9 | @Component({
10 | selector: 'signup-cmp',
11 | providers: [SignupService],
12 | templateUrl: 'signup.component.html',
13 | styleUrls: ['./signup.component.scss']
14 | })
15 |
16 | export class SignupComponent {
17 | public userModel = {}
18 |
19 | constructor(private router: Router, private signupService: SignupService) {}
20 | onSubmit() {
21 | this.signupService.signup(this.userModel).then(res => {
22 | if (res) this.router.navigate(['/'])
23 | })
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/app/signup/signup.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core'
2 | // import { Observable } from 'rxjs/Observable'
3 | import { SocketService } from '../app.service'
4 |
5 |
6 | @Injectable()
7 | export class SignupService {
8 | // public item$: Observable
9 | // private _observable
10 | private userService
11 |
12 | constructor(private userServiceService: SocketService) {
13 | // get featheres service
14 | this.userService = userServiceService.getService('users')
15 |
16 | // this.item$ is a public observable for components to subscribe
17 | // this.item$ = new Observable(observable => this._observable = observable)
18 | }
19 |
20 | signup(user: any) {
21 | return this.userService.create({
22 | email: user.email,
23 | password: user.password
24 | })
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/client/app/widgets/index.ts:
--------------------------------------------------------------------------------
1 | export * from './todo/index'
2 | export * from './stats/index'
3 |
--------------------------------------------------------------------------------
/client/app/widgets/todo/index.ts:
--------------------------------------------------------------------------------
1 | export * from './todo'
2 |
--------------------------------------------------------------------------------
/client/app/widgets/todo/todo.html:
--------------------------------------------------------------------------------
1 |
2 | To do Tasks
3 |
4 |
5 |
6 | {{name}}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/client/app/widgets/todo/todo.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core'
2 |
3 | @Component({
4 | selector: 'todo-cmp',
5 | templateUrl: './todo.html'
6 | })
7 |
8 | export class TodoComponent implements OnInit {
9 | newName: string
10 | nameList: any = [
11 | 'Meeting with Bryan.',
12 | 'Exercise at 6:pm with Yoga.',
13 | 'Lunch Lunch Lunch.',
14 | 'Her birthday at riverside.'
15 | ]
16 | addName(): boolean {
17 | this.nameList.push(this.newName)
18 | this.newName = ''
19 | return true
20 | }
21 | ngOnInit() {
22 | // let todoListWraper: any = $('.todo-list-wrap')
23 | // todoListWraper.perfectScrollbar({})
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/favicon.ico
--------------------------------------------------------------------------------
/client/assets/icon/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/android-icon-144x144.png
--------------------------------------------------------------------------------
/client/assets/icon/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/android-icon-192x192.png
--------------------------------------------------------------------------------
/client/assets/icon/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/android-icon-36x36.png
--------------------------------------------------------------------------------
/client/assets/icon/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/android-icon-48x48.png
--------------------------------------------------------------------------------
/client/assets/icon/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/android-icon-72x72.png
--------------------------------------------------------------------------------
/client/assets/icon/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/android-icon-96x96.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-114x114.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-120x120.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-144x144.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-152x152.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-180x180.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-57x57.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-60x60.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-72x72.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-76x76.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/client/assets/icon/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/apple-icon.png
--------------------------------------------------------------------------------
/client/assets/icon/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/client/assets/icon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/favicon-16x16.png
--------------------------------------------------------------------------------
/client/assets/icon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/favicon-32x32.png
--------------------------------------------------------------------------------
/client/assets/icon/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/favicon-96x96.png
--------------------------------------------------------------------------------
/client/assets/icon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/favicon.ico
--------------------------------------------------------------------------------
/client/assets/icon/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/ms-icon-144x144.png
--------------------------------------------------------------------------------
/client/assets/icon/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/ms-icon-150x150.png
--------------------------------------------------------------------------------
/client/assets/icon/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/ms-icon-310x310.png
--------------------------------------------------------------------------------
/client/assets/icon/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/assets/icon/ms-icon-70x70.png
--------------------------------------------------------------------------------
/client/config/config.common.ts:
--------------------------------------------------------------------------------
1 | export const commonConfig = {
2 | port: 80,
3 | tokenKey: 'famn-jwt'
4 | }
5 |
--------------------------------------------------------------------------------
/client/config/config.dev.ts:
--------------------------------------------------------------------------------
1 | import { commonConfig } from './config.common'
2 |
3 | export const devConfig = Object.assign({}, commonConfig, {
4 | port: '3030'
5 | })
6 |
--------------------------------------------------------------------------------
/client/config/config.prod.ts:
--------------------------------------------------------------------------------
1 | import { commonConfig } from './config.common'
2 |
3 | export const prodConfig = Object.assign({}, commonConfig, {
4 | port: '8080'
5 | })
6 |
--------------------------------------------------------------------------------
/client/config/config.ts:
--------------------------------------------------------------------------------
1 | import { devConfig } from './config.dev'
2 | import { prodConfig } from './config.prod'
3 |
4 | interface ClientConfig {
5 | port: string,
6 | tokenKey: string
7 | }
8 |
9 | let config: ClientConfig
10 |
11 | switch (ENV) {
12 | case 'production':
13 | case 'prod':
14 | config = prodConfig
15 | break
16 | case 'development':
17 | case 'dev':
18 | config = devConfig
19 | break
20 | default:
21 | break
22 | }
23 |
24 | export { config }
25 |
--------------------------------------------------------------------------------
/client/config/empty.ts:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NgProbeToken: {},
3 | HmrState: function() {},
4 | _createConditionalRootRenderer: function(rootRenderer, extraTokens, coreTokens) {
5 | return rootRenderer;
6 | },
7 | __platform_browser_private__: {}
8 | };
9 |
--------------------------------------------------------------------------------
/client/config/helpers.ts:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 |
4 | const EVENT = process.env.npm_lifecycle_event || ''
5 |
6 | // Helper functions
7 | const ROOT = path.resolve(__dirname, '../..')
8 |
9 | function hasProcessFlag(flag) {
10 | return process.argv.join('').indexOf(flag) > -1
11 | }
12 |
13 | function hasNpmFlag(flag) {
14 | return EVENT.includes(flag)
15 | }
16 |
17 | function isWebpackDevServer() {
18 | return process.argv[1] && !! (/webpack-dev-server$/.exec(process.argv[1]))
19 | }
20 |
21 | function root(args) {
22 | args = Array.prototype.slice.call(arguments, 0)
23 | return path.join.apply(path, [ROOT].concat(args))
24 | }
25 |
26 | function checkNodeImport(context, request, cb) {
27 | if (!path.isAbsolute(request) && request.charAt(0) !== '.') {
28 | cb(null, 'commonjs ' + request)
29 | return
30 | }
31 | cb()
32 | }
33 |
34 |
35 | // exports.hasProcessFlag = hasProcessFlag
36 | // exports.isWebpackDevServer = isWebpackDevServer
37 | // exports.root = root
38 | // exports.checkNodeImport = checkNodeImport
39 |
40 | function getHost() {
41 | return location.host
42 | }
43 |
44 | export const helpers = {
45 | hasProcessFlag,
46 | hasNpmFlag,
47 | isWebpackDevServer,
48 | root,
49 | checkNodeImport,
50 | getHost
51 | }
52 |
--------------------------------------------------------------------------------
/client/config/html-elements-plugin/index.ts:
--------------------------------------------------------------------------------
1 |
2 | function HtmlElementsPlugin(locations) {
3 | this.locations = locations;
4 | }
5 |
6 | HtmlElementsPlugin.prototype.apply = function(compiler) {
7 | var self = this;
8 | compiler.plugin('compilation', function(compilation) {
9 | compilation.options.htmlElements = compilation.options.htmlElements || {};
10 |
11 | compilation.plugin('html-webpack-plugin-before-html-generation', function(htmlPluginData, callback) {
12 | const locations = self.locations;
13 |
14 | if (locations) {
15 | const publicPath = htmlPluginData.assets.publicPath;
16 |
17 | Object.getOwnPropertyNames(locations).forEach(function(loc) {
18 | compilation.options.htmlElements[loc] = getHtmlElementString(locations[loc], publicPath);
19 | });
20 | }
21 |
22 |
23 | callback(null, htmlPluginData);
24 | });
25 | });
26 |
27 | };
28 |
29 | const RE_ENDS_WITH_BS = /\/$/;
30 |
31 | /**
32 | * Create an HTML tag with attributes from a map.
33 | *
34 | * Example:
35 | * createTag('link', { rel: "manifest", href: "/assets/manifest.json" })
36 | * //
37 | * @param tagName The name of the tag
38 | * @param attrMap A Map of attribute names (keys) and their values.
39 | * @param publicPath a path to add to eh start of static asset url
40 | * @returns {string}
41 | */
42 | function createTag(tagName, attrMap, publicPath) {
43 | publicPath = publicPath || '';
44 |
45 | // add trailing slash if we have a publicPath and it doesn't have one.
46 | if (publicPath && !RE_ENDS_WITH_BS.test(publicPath)) {
47 | publicPath += '/';
48 | }
49 |
50 | const attributes = Object.getOwnPropertyNames(attrMap)
51 | .filter(function(name) { return name[0] !== '='; } )
52 | .map(function(name) {
53 | var value = attrMap[name];
54 |
55 | if (publicPath) {
56 | // check if we have explicit instruction, use it if so (e.g: =herf: false)
57 | // if no instruction, use public path if it's href attribute.
58 | const usePublicPath = attrMap.hasOwnProperty('=' + name) ? !!attrMap['=' + name] : name === 'href';
59 |
60 | if (usePublicPath) {
61 | // remove a starting trailing slash if the value has one so we wont have //
62 | value = publicPath + (value[0] === '/' ? value.substr(1) : value);
63 | }
64 | }
65 |
66 | return name + '="' + value + '"';
67 | });
68 |
69 | return '<' + tagName + ' ' + attributes.join(' ') + '>';
70 | }
71 |
72 | /**
73 | * Returns a string representing all html elements defined in a data source.
74 | *
75 | * Example:
76 | *
77 | * const ds = {
78 | * link: [
79 | * { rel: "apple-touch-icon", sizes: "57x57", href: "/assets/icon/apple-icon-57x57.png" }
80 | * ],
81 | * meta: [
82 | * { name: "msapplication-TileColor", content: "#00bcd4" }
83 | * ]
84 | * }
85 | *
86 | * getHeadTags(ds);
87 | * // ""
88 | * ""
89 | *
90 | * @returns {string}
91 | */
92 | function getHtmlElementString(dataSource, publicPath) {
93 | return Object.getOwnPropertyNames(dataSource)
94 | .map(function(name) {
95 | if (Array.isArray(dataSource[name])) {
96 | return dataSource[name].map(function(attrs) { return createTag(name, attrs, publicPath); } );
97 | } else {
98 | return [ createTag(name, dataSource[name], publicPath) ];
99 | }
100 | })
101 | .reduce(function(arr, curr) {
102 | return arr.concat(curr);
103 | }, [])
104 | .join('\n\t');
105 | }
106 | module.exports = HtmlElementsPlugin;
107 |
--------------------------------------------------------------------------------
/client/config/html-head-config.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Configuration for head elements added during the creation of index.html.
3 | *
4 | * All href attributes are added the publicPath (if exists) by default.
5 | * You can explicitly hint to prefix a publicPath by setting a boolean value to a key that has
6 | * the same name as the attribute you want to operate on, but prefix with =
7 | *
8 | * Example:
9 | * { name: 'msapplication-TileImage', content: '/assets/icon/ms-icon-144x144.png', '=content': true },
10 | * Will prefix the publicPath to content.
11 | *
12 | * { rel: 'apple-touch-icon', sizes: '57x57', href: '/assets/icon/apple-icon-57x57.png', '=href': false },
13 | * Will not prefix the publicPath on href (href attributes are added by default
14 | *
15 | */
16 | export const headTags = {
17 | link: [
18 | /** tags for 'apple-touch-icon' (AKA Web Clips). **/
19 | // { rel: 'apple-touch-icon', sizes: '57x57', href: '/assets/icon/apple-icon-57x57.png' },
20 | // { rel: 'apple-touch-icon', sizes: '60x60', href: '/assets/icon/apple-icon-60x60.png' },
21 | // { rel: 'apple-touch-icon', sizes: '72x72', href: '/assets/icon/apple-icon-72x72.png' },
22 | // { rel: 'apple-touch-icon', sizes: '76x76', href: '/assets/icon/apple-icon-76x76.png' },
23 | // { rel: 'apple-touch-icon', sizes: '114x114', href: '/assets/icon/apple-icon-114x114.png' },
24 | // { rel: 'apple-touch-icon', sizes: '120x120', href: '/assets/icon/apple-icon-120x120.png' },
25 | // { rel: 'apple-touch-icon', sizes: '144x144', href: '/assets/icon/apple-icon-144x144.png' },
26 | // { rel: 'apple-touch-icon', sizes: '152x152', href: '/assets/icon/apple-icon-152x152.png' },
27 | // { rel: 'apple-touch-icon', sizes: '180x180', href: '/assets/icon/apple-icon-180x180.png' },
28 |
29 | /** tags for android web app icons **/
30 | // { rel: 'icon', type: 'image/png', sizes: '192x192', href: '/assets/icon/android-icon-192x192.png' },
31 |
32 | /** tags for favicons **/
33 | // { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/assets/icon/favicon-32x32.png' },
34 | // { rel: 'icon', type: 'image/png', sizes: '96x96', href: '/assets/icon/favicon-96x96.png' },
35 | // { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/assets/icon/favicon-16x16.png' },
36 | { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/assets/favicon.ico' },
37 |
38 | /** tags for a Web App Manifest **/
39 | { rel: 'manifest', href: '/assets/manifest.json' },
40 |
41 | /**
42 | * tags for web font, stylesheet
43 | */
44 | {
45 | rel: 'stylesheet',
46 | type: 'text/css',
47 | href: 'https://fonts.googleapis.com/css?family=Roboto:400,30',
48 | },
49 | {
50 | rel: 'stylesheet',
51 | href: 'https://fonts.googleapis.com/icon?family=Material+Icons',
52 | }
53 | ],
54 | meta: [
55 | { name: 'msapplication-TileColor', content: '#00bcd4' },
56 | { name: 'msapplication-TileImage', content: '/assets/icon/ms-icon-144x144.png', '=content': true },
57 | { name: 'theme-color', content: '#00bcd4' }
58 | ],
59 | };
60 |
--------------------------------------------------------------------------------
/client/config/resource-override.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/implustech/famn/a671782665d2da31213b328a0918608d27b542cc/client/config/resource-override.ts
--------------------------------------------------------------------------------
/client/config/webpack.common.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @author: hjl
3 | */
4 |
5 | const webpack = require('webpack')
6 | import { helpers } from './helpers'
7 | import { headTags } from './html-head-config'
8 |
9 | /*
10 | * Webpack Plugins
11 | */
12 | // problem with copy-webpack-plugin
13 | const CopyWebpackPlugin = require('copy-webpack-plugin')
14 | const AssetsPlugin = require('assets-webpack-plugin')
15 | const HtmlWebpackPlugin = require('html-webpack-plugin')
16 | const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin
17 | const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
18 | const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin')
19 | const HtmlElementsPlugin = require('./html-elements-plugin')
20 | const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin')
21 | const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin')
22 | const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
23 | const ngcWebpack = require('ngc-webpack')
24 |
25 |
26 | /*
27 | * Webpack Constants
28 | */
29 | const ENV = process.env.ENV = process.env.NODE_ENV = 'development'
30 | const HMR = helpers.hasProcessFlag('hot')
31 | const AOT = helpers.hasNpmFlag('aot')
32 | const METADATA = {
33 | title: 'FAMN Angular2 client-server boilerplate',
34 | baseUrl: '/',
35 | isDevServer: helpers.isWebpackDevServer()
36 | }
37 |
38 | /*
39 | * Webpack configuration
40 | *
41 | * See: http://webpack.github.io/docs/configuration.html#cli
42 | */
43 | export function webpackCommonConfig(options) {
44 | let isProd = options.env === 'production'
45 | return {
46 |
47 | /*
48 | * Cache generated modules and chunks to improve performance for multiple incremental builds.
49 | * This is enabled by default in watch mode.
50 | * You can pass false to disable it.
51 | *
52 | * See: http://webpack.github.io/docs/configuration.html#cache
53 | */
54 | //cache: false,
55 |
56 | /*
57 | * The entry point for the bundle
58 | * Our Angular.js app
59 | *
60 | * See: http://webpack.github.io/docs/configuration.html#entry
61 | */
62 | entry: {
63 | 'polyfills': './client/polyfills.ts',
64 | 'main': AOT ? './client/main.aot.ts' : './client/main.ts'
65 | },
66 |
67 | /*
68 | * Options affecting the resolving of modules.
69 | *
70 | * See: https://webpack.github.io/docs/configuration.html#externals
71 | */
72 | externals: {
73 | jquery: 'jQuery'
74 | },
75 |
76 | /*
77 | * Options affecting the resolving of modules.
78 | *
79 | * See: http://webpack.github.io/docs/configuration.html#resolve
80 | */
81 | resolve: {
82 |
83 | /*
84 | * An array of extensions that should be used to resolve modules.
85 | *
86 | * See: http://webpack.github.io/docs/configuration.html#resolve-extensions
87 | */
88 | extensions: ['.ts', '.js', '.json'],
89 | modules: [helpers.root('client/app'), helpers.root('node_modules')],
90 | },
91 |
92 | /*
93 | * Options affecting the normal modules.
94 | *
95 | * See: http://webpack.github.io/docs/configuration.html#module
96 | */
97 | module: {
98 |
99 | rules: [
100 |
101 | /*
102 | * Typescript loader support for .ts
103 | *
104 | * Component Template/Style integration using `angular2-template-loader`
105 | * Angular 2 lazy loading (async routes) via `ng-router-loader`
106 | *
107 | * `ng-router-loader` expects vanilla JavaScript code, not TypeScript code. This is why the
108 | * order of the loader matter.
109 | *
110 | * See: https://github.com/s-panferov/awesome-typescript-loader
111 | * See: https://github.com/TheLarkInn/angular2-template-loader
112 | * See: https://github.com/shlomiassaf/ng-router-loader
113 | */
114 | {
115 | test: /\.ts$/,
116 | use: [
117 | {
118 | loader: '@angularclass/hmr-loader',
119 | options: {
120 | pretty: !isProd,
121 | prod: isProd
122 | }
123 | },
124 | { // MAKE SURE TO CHAIN VANILLA JS CODE, I.E. TS COMPILATION OUTPUT.
125 | loader: 'ng-router-loader',
126 | options: {
127 | loader: 'async-import',
128 | genDir: 'aot',
129 | aot: AOT
130 | }
131 | },
132 | {
133 | loader: 'awesome-typescript-loader',
134 | options: {
135 | configFileName: 'tsconfig.client.json'
136 | }
137 | },
138 | {
139 | loader: 'angular2-template-loader'
140 | }
141 | ],
142 | exclude: [/\.(spec|e2e)\.ts$/]
143 | },
144 |
145 | /*
146 | * Json loader support for *.json files.
147 | *
148 | * See: https://github.com/webpack/json-loader
149 | */
150 | {
151 | test: /\.json$/,
152 | use: 'json-loader'
153 | },
154 |
155 | /*
156 | * to string and css loader support for *.css files
157 | * Returns file content as string
158 | *
159 | */
160 | {
161 | test: /\.css$/,
162 | // loaders: ['to-string-loader', 'css-loader']
163 | use: ['style-loader', 'css-loader']
164 | },
165 |
166 | /*
167 | * to string and sass loader support for *.sass files
168 | * Returns file content as string
169 | *
170 | */
171 | {
172 | test: /\.scss$/,
173 | exclude: /node_modules|global/,
174 | use: ['raw-loader', 'sass-loader']
175 | },
176 | {
177 | test: /global\.scss$/,
178 | use: ['style-loader', 'css-loader', 'sass-loader']
179 | },
180 |
181 | /* Raw loader support for *.html
182 | * Returns file content as string
183 | *
184 | * See: https://github.com/webpack/raw-loader
185 | */
186 | {
187 | test: /\.html$/,
188 | use: 'raw-loader',
189 | exclude: [helpers.root('client/index.html')]
190 | },
191 |
192 | /* File loader for supporting images, for example, in CSS files.
193 | */
194 | {
195 | test: /\.(jpg|png|gif)$/,
196 | use: 'file-loader'
197 | },
198 | {
199 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
200 | use: 'url?limit=10000&minetype=application/font-woff'
201 | },
202 | {
203 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
204 | use: 'url?limit=10000&minetype=application/font-woff'
205 | },
206 | {
207 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
208 | use: 'url?limit=10000&minetype=application/octet-stream'
209 | },
210 | {
211 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
212 | use: 'file'
213 | },
214 | {
215 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
216 | use: 'url?limit=10000&minetype=image/svg+xml'
217 | },
218 | {
219 | test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i,
220 | use: 'url?limit=10000'
221 | },
222 | ]
223 | },
224 |
225 | /*
226 | * Add additional plugins to the compiler.
227 | *
228 | * See: http://webpack.github.io/docs/configuration.html#plugins
229 | */
230 | plugins: [
231 | new AssetsPlugin({
232 | path: helpers.root('dist'),
233 | filename: 'webpack-assets.json',
234 | prettyPrint: true
235 | }),
236 |
237 | /*
238 | * Plugin: ForkCheckerPlugin
239 | * Description: Do type checking in a separate process, so webpack don't need to wait.
240 | *
241 | * See: https://github.com/s-panferov/awesome-typescript-loader#forkchecker-boolean-defaultfalse
242 | */
243 | new CheckerPlugin(),
244 | /*
245 | * Plugin: CommonsChunkPlugin
246 | * Description: Shares common code between the pages.
247 | * It identifies common modules and put them into a commons chunk.
248 | *
249 | * See: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
250 | * See: https://github.com/webpack/docs/wiki/optimization#multi-page-app
251 | */
252 | new CommonsChunkPlugin({
253 | name: ['polyfills'],
254 | chunks: ['polyfills']
255 | }),
256 | // This enables tree shaking of the vendor modules
257 | new CommonsChunkPlugin({
258 | name: 'vendor',
259 | chunks: ['main'],
260 | minChunks: module => /node_modules/.test(module.resource)
261 | }),
262 | // Specify the correct order the scripts will be injected in
263 | new CommonsChunkPlugin({
264 | name: ['polyfills', 'vendor'].reverse()
265 | }),
266 |
267 | /**
268 | * Plugin: ContextReplacementPlugin
269 | * Description: Provides context to Angular's use of System.import
270 | *
271 | * See: https://webpack.github.io/docs/list-of-plugins.html#contextreplacementplugin
272 | * See: https://github.com/angular/angular/issues/11580
273 | */
274 | new ContextReplacementPlugin(
275 | // The (\\|\/) piece accounts for path separators in *nix and Windows
276 | /angular(\\|\/)core(\\|\/)src(\\|\/)linker/,
277 | helpers.root('client') // location of your src
278 | ),
279 |
280 | new webpack.ProvidePlugin({
281 | $: 'jquery'
282 | }),
283 |
284 | /*
285 | * Plugin: CopyWebpackPlugin
286 | * Description: Copy files and directories in webpack.
287 | *
288 | * Copies project static assets.
289 | *
290 | * See: https://www.npmjs.com/package/copy-webpack-plugin
291 | */
292 | new CopyWebpackPlugin([{
293 | from: 'client/assets',
294 | to: 'assets'
295 | }, {
296 | from: 'client/assets/favicon.ico',
297 | to: 'favicon.ico'
298 | }, {
299 | from: 'client/app/meta.json',
300 | to: 'meta.json'
301 | }]),
302 |
303 | /*
304 | * Plugin: HtmlWebpackPlugin
305 | * Description: Simplifies creation of HTML files to serve your webpack bundles.
306 | * This is especially useful for webpack bundles that include a hash in the filename
307 | * which changes every compilation.
308 | *
309 | * See: https://github.com/ampedandwired/html-webpack-plugin
310 | */
311 | new HtmlWebpackPlugin({
312 | template: 'client/index.html',
313 | title: METADATA.title,
314 | chunksSortMode: 'dependency',
315 | metadata: METADATA,
316 | inject: 'head'
317 | }),
318 |
319 |
320 | /*
321 | * Plugin: ScriptExtHtmlWebpackPlugin
322 | * Description: Enhances html-webpack-plugin functionality
323 | * with different deployment options for your scripts including:
324 | *
325 | * See: https://github.com/numical/script-ext-html-webpack-plugin
326 | */
327 | new ScriptExtHtmlWebpackPlugin({
328 | defaultAttribute: 'defer'
329 | }),
330 |
331 |
332 |
333 | /*
334 | * Plugin: HtmlHeadConfigPlugin
335 | * Description: Generate html tags based on javascript maps.
336 | *
337 | * If a publicPath is set in the webpack output configuration, it will be automatically added to
338 | * href attributes, you can disable that by adding a "=href": false property.
339 | * You can also enable it to other attribute by settings "=attName": true.
340 | *
341 | * The configuration supplied is map between a location (key) and an element definition object (value)
342 | * The location (key) is then exported to the template under then htmlElements property in webpack configuration.
343 | *
344 | * Example:
345 | * Adding this plugin configuration
346 | * new HtmlElementsPlugin({
347 | * headTags: { ... }
348 | * })
349 | *
350 | * Means we can use it in the template like this:
351 | * <%= webpackConfig.htmlElements.headTags %>
352 | *
353 | * Dependencies: HtmlWebpackPlugin
354 | */
355 | new HtmlElementsPlugin({
356 | headTags: headTags
357 | }),
358 |
359 | /**
360 | * Plugin LoaderOptionsPlugin (experimental)
361 | *
362 | * See: https://gist.github.com/sokra/27b24881210b56bbaff7
363 | */
364 | new LoaderOptionsPlugin({}),
365 |
366 |
367 | // Fix Angular 2
368 | new NormalModuleReplacementPlugin(
369 | /facade(\\|\/)async/,
370 | helpers.root('node_modules/@angular/core/src/facade/async.js')
371 | ),
372 | new NormalModuleReplacementPlugin(
373 | /facade(\\|\/)collection/,
374 | helpers.root('node_modules/@angular/core/src/facade/collection.js')
375 | ),
376 | new NormalModuleReplacementPlugin(
377 | /facade(\\|\/)errors/,
378 | helpers.root('node_modules/@angular/core/src/facade/errors.js')
379 | ),
380 | new NormalModuleReplacementPlugin(
381 | /facade(\\|\/)lang/,
382 | helpers.root('node_modules/@angular/core/src/facade/lang.js')
383 | ),
384 | new NormalModuleReplacementPlugin(
385 | /facade(\\|\/)math/,
386 | helpers.root('node_modules/@angular/core/src/facade/math.js')
387 | ),
388 |
389 | new ngcWebpack.NgcWebpackPlugin({
390 | disabled: !AOT,
391 | tsConfig: helpers.root('tsconfig.webpack.json'),
392 | resourceOverride: helpers.root('./client/config/resource-override.ts')
393 | })
394 |
395 | ],
396 |
397 |
398 | /*
399 | * Include polyfills or mocks for various node stuff
400 | * Description: Node configuration
401 | *
402 | * See: https://webpack.github.io/docs/configuration.html#node
403 | */
404 | node: {
405 | global: true,
406 | crypto: 'empty',
407 | process: true,
408 | module: false,
409 | clearImmediate: false,
410 | setImmediate: false
411 | }
412 | }
413 | }
414 |
--------------------------------------------------------------------------------
/client/config/webpack.dev.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @author: hjl
3 | */
4 |
5 | const webpack = require('webpack')
6 | const webpackMerge = require('webpack-merge') // used to merge webpack configs
7 | const webpackMergeDll = webpackMerge.strategy({ plugins: 'replace' })
8 | import { helpers } from './helpers'
9 | import { webpackCommonConfig } from './webpack.common' // the settings that are common to prod and dev
10 |
11 | /**
12 | * Webpack Plugins
13 | */
14 | const DefinePlugin = require('webpack/lib/DefinePlugin')
15 | const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin')
16 | const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
17 | const NamedModulesPlugin = require('webpack/lib/NamedModulesPlugin')
18 | const DllBundlesPlugin = require('webpack-dll-bundles-plugin').DllBundlesPlugin
19 |
20 |
21 |
22 |
23 |
24 | /**
25 | * Webpack Constants
26 | */
27 | const ENV = process.env.ENV = process.env.NODE_ENV = 'development'
28 | const HOST = process.env.HOST || 'localhost'
29 | const PORT = process.env.PORT || 3030
30 | const HMR = process.env.HMR
31 | // const METADATA = webpackMerge(commonConfig({ env: ENV }).metadata, {
32 | const METADATA = webpackMerge({}, {
33 | host: HOST,
34 | port: PORT,
35 | ENV: ENV,
36 | HMR: HMR
37 | })
38 |
39 |
40 |
41 | /**
42 | * Webpack configuration
43 | *
44 | * See: http://webpack.github.io/docs/configuration.html#cli
45 | */
46 |
47 |
48 | export default webpackMerge(webpackCommonConfig({ env: ENV }), {
49 |
50 |
51 | /**
52 | * Merged metadata from webpack.common.js for index.html
53 | *
54 | * See: (custom attribute)
55 | */
56 | // metadata: METADATA,
57 |
58 | /*
59 | * The entry point for the bundle
60 | * Our Angular.js app
61 | *
62 | * See: http://webpack.github.io/docs/configuration.html#entry
63 | */
64 | entry: {
65 | // 'polyfills': ['./client/polyfills.ts'].concat(HMR ? ['webpack-hot-middleware/client'] : []),
66 | 'polyfills': ['./client/polyfills.ts'],
67 | 'main': ['./client/main.ts'].concat(HMR ? ['webpack-hot-middleware/client'] : []),
68 | },
69 |
70 |
71 |
72 | /**
73 | * Developer tool to enhance debugging
74 | *
75 | * See: http://webpack.github.io/docs/configuration.html#devtool
76 | * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
77 | */
78 | devtool: 'cheap-module-source-map',
79 |
80 | /**
81 | * Options affecting the output of the compilation.
82 | *
83 | * See: http://webpack.github.io/docs/configuration.html#output
84 | */
85 | output: {
86 |
87 | /**
88 | * The output directory as absolute path (required).
89 | *
90 | * See: http://webpack.github.io/docs/configuration.html#output-path
91 | */
92 | path: helpers.root('dist/client'),
93 |
94 | /**
95 | * Specifies the name of each output file on disk.
96 | * IMPORTANT: You must not specify an absolute path here!
97 | *
98 | * See: http://webpack.github.io/docs/configuration.html#output-filename
99 | */
100 | filename: '[name].bundle.js',
101 |
102 | /**
103 | * The filename of the SourceMaps for the JavaScript files.
104 | * They are inside the output.path directory.
105 | *
106 | * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename
107 | */
108 | sourceMapFilename: '[file].map',
109 |
110 | /** The filename of non-entry chunks as relative path
111 | * inside the output.path directory.
112 | *
113 | * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename
114 | */
115 | chunkFilename: '[id].chunk.js',
116 |
117 | library: 'ac_[name]',
118 | libraryTarget: 'var',
119 | },
120 |
121 | plugins: [
122 |
123 | /**
124 | * Plugin: DefinePlugin
125 | * Description: Define free variables.
126 | * Useful for having development builds with debug logging or adding global constants.
127 | *
128 | * Environment helpers
129 | *
130 | * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
131 | */
132 | // NOTE: when adding more properties, make sure you include them in custom-typings.d.ts
133 | new DefinePlugin({
134 | 'ENV': JSON.stringify(METADATA.ENV),
135 | 'HMR': METADATA.HMR,
136 | 'process.env': {
137 | 'ENV': JSON.stringify(METADATA.ENV),
138 | 'NODE_ENV': JSON.stringify(METADATA.ENV),
139 | 'HMR': METADATA.HMR,
140 | }
141 | }),
142 |
143 | new DllBundlesPlugin({
144 | bundles: {
145 | polyfills: [
146 | 'core-js',
147 | {
148 | name: 'zone.js',
149 | path: 'zone.js/dist/zone.js'
150 | },
151 | {
152 | name: 'zone.js',
153 | path: 'zone.js/dist/long-stack-trace-zone.js'
154 | }
155 | ],
156 | vendor: [
157 | '@angular/platform-browser',
158 | '@angular/platform-browser-dynamic',
159 | '@angular/core',
160 | '@angular/common',
161 | '@angular/forms',
162 | '@angular/http',
163 | '@angular/router',
164 | '@angularclass/hmr',
165 | 'socket.io-client',
166 | 'feathers',
167 | 'feathers-socketio',
168 | 'feathers-hooks',
169 | 'feathers-authentication-client',
170 | 'rxjs',
171 | ]
172 | },
173 | dllDir: helpers.root('dll'),
174 | webpackConfig: webpackMergeDll(webpackCommonConfig({ env: ENV }), {
175 | devtool: 'cheap-module-source-map',
176 | plugins: []
177 | })
178 | }),
179 |
180 | /**
181 | * Plugin: AddAssetHtmlPlugin
182 | * Description: Adds the given JS or CSS file to the files
183 | * Webpack knows about, and put it into the list of assets
184 | * html-webpack-plugin injects into the generated html.
185 | *
186 | * See: https://github.com/SimenB/add-asset-html-webpack-plugin
187 | */
188 | new AddAssetHtmlPlugin([
189 | { filepath: helpers.root(`dll/${DllBundlesPlugin.resolveFile('polyfills')}`) },
190 | { filepath: helpers.root(`dll/${DllBundlesPlugin.resolveFile('vendor')}`) }
191 | ]),
192 |
193 |
194 | /**
195 | * Plugin LoaderOptionsPlugin (experimental)
196 | *
197 | * See: https://gist.github.com/sokra/27b24881210b56bbaff7
198 | */
199 | new LoaderOptionsPlugin({
200 | debug: true,
201 | options: {
202 | }
203 | }),
204 |
205 |
206 | // Used with webpack-hot-middllware
207 | new webpack.HotModuleReplacementPlugin(),
208 | new webpack.NoEmitOnErrorsPlugin()
209 |
210 | ],
211 |
212 | /**
213 | * Webpack Development Server configuration
214 | * Description: The webpack-dev-server is a little node.js Express server.
215 | * The server emits information about the compilation state to the client,
216 | * which reacts to those events.
217 | *
218 | * See: https://webpack.github.io/docs/webpack-dev-server.html
219 | */
220 | devServer: {
221 | port: METADATA.port,
222 | host: METADATA.host,
223 | historyApiFallback: true,
224 | watchOptions: {
225 | aggregateTimeout: 300,
226 | poll: 1000
227 | },
228 | outputPath: helpers.root('dist/client')
229 | },
230 |
231 | /*
232 | * Include polyfills or mocks for various node stuff
233 | * Description: Node configuration
234 | *
235 | * See: https://webpack.github.io/docs/configuration.html#node
236 | */
237 | node: {
238 | global: true,
239 | crypto: 'empty',
240 | process: true,
241 | module: false,
242 | clearImmediate: false,
243 | setImmediate: false
244 | }
245 | })
246 |
--------------------------------------------------------------------------------
/client/config/webpack.prod.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @author: hjl
3 | */
4 |
5 | import { helpers } from './helpers'
6 | const webpackMerge = require('webpack-merge') // used to merge webpack configs
7 | import { webpackCommonConfig } from './webpack.common' // the settings that are common to prod and dev
8 |
9 | /**
10 | * Webpack Plugins
11 | */
12 | const DefinePlugin = require('webpack/lib/DefinePlugin')
13 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
14 | const IgnorePlugin = require('webpack/lib/IgnorePlugin')
15 | const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin')
16 | const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin')
17 | const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin')
18 | const ProvidePlugin = require('webpack/lib/ProvidePlugin')
19 | const OptimizeJsPlugin = require('optimize-js-plugin')
20 |
21 | /**
22 | * Webpack Constants
23 | */
24 | const ENV = process.env.ENV = process.env.NODE_ENV = 'production'
25 | const HOST = process.env.HOST || 'localhost'
26 | const PORT = process.env.PORT || 8080
27 | // const METADATA = webpackMerge(commonConfig({ env: ENV }).metadata, {
28 | const METADATA = webpackMerge({}, {
29 | host: HOST,
30 | port: PORT,
31 | ENV: ENV,
32 | HMR: undefined
33 | })
34 |
35 | /**
36 | * Webpack configuration
37 | *
38 | * See: http://webpack.github.io/docs/configuration.html#cli
39 | */
40 |
41 | export default webpackMerge(webpackCommonConfig({ env: ENV }), {
42 |
43 | /**
44 | * Developer tool to enhance debugging
45 | * See: http://webpack.github.io/docs/configuration.html#devtool
46 | * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
47 | */
48 | devtool: 'source-map',
49 |
50 | /**
51 | * Options affecting the output of the compilation.
52 | *
53 | * See: http://webpack.github.io/docs/configuration.html#output
54 | */
55 | output: {
56 |
57 | /**
58 | * The output directory as absolute path (required).
59 | *
60 | * See: http://webpack.github.io/docs/configuration.html#output-path
61 | */
62 | path: helpers.root('dist/client'),
63 |
64 | /**
65 | * Specifies the name of each output file on disk.
66 | * IMPORTANT: You must not specify an absolute path here!
67 | *
68 | * See: http://webpack.github.io/docs/configuration.html#output-filename
69 | */
70 | filename: '[name].[chunkhash].bundle.js',
71 |
72 | /**
73 | * The filename of the SourceMaps for the JavaScript files.
74 | * They are inside the output.path directory.
75 | *
76 | * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename
77 | */
78 | sourceMapFilename: '[name].[chunkhash].bundle.map',
79 |
80 | /** The filename of non-entry chunks as relative path
81 | * inside the output.path directory.
82 | *
83 | * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename
84 | */
85 | chunkFilename: '[id].[chunkhash].chunk.js'
86 | },
87 |
88 | plugins: [
89 |
90 | /**
91 | * Webpack plugin to optimize a JavaScript file for faster initial load
92 | * by wrapping eagerly-invoked functions.
93 | *
94 | * See: https://github.com/vigneshshanmugam/optimize-js-plugin
95 | */
96 |
97 | new OptimizeJsPlugin({
98 | sourceMap: false
99 | }),
100 |
101 | new ExtractTextPlugin('[name].[contenthash].css'),
102 |
103 |
104 | /**
105 | * Plugin: DefinePlugin
106 | * Description: Define free variables.
107 | * Useful for having development builds with debug logging or adding global constants.
108 | *
109 | * Environment helpers
110 | *
111 | * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
112 | */
113 | // NOTE: when adding more properties, make sure you include them in custom-typings.d.ts
114 | new DefinePlugin({
115 | 'ENV': JSON.stringify(METADATA.ENV),
116 | 'HMR': METADATA.HMR,
117 | 'process.env': {
118 | 'ENV': JSON.stringify(METADATA.ENV),
119 | 'NODE_ENV': JSON.stringify(METADATA.ENV),
120 | 'HMR': METADATA.HMR,
121 | }
122 | }),
123 |
124 |
125 | /**
126 | * Plugin: UglifyJsPlugin
127 | * Description: Minimize all JavaScript output of chunks.
128 | * Loaders are switched into minimizing mode.
129 | *
130 | * See: https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
131 | */
132 | // NOTE: To debug prod builds uncomment //debug lines and comment //prod lines
133 | new UglifyJsPlugin({
134 | beautify: false, //prod
135 | output: {
136 | comments: false
137 | }, //prod
138 | mangle: {
139 | screw_ie8: true
140 | }, //prod
141 | compress: {
142 | screw_ie8: true,
143 | warnings: false,
144 | conditionals: true,
145 | unused: true,
146 | comparisons: true,
147 | sequences: true,
148 | dead_code: true,
149 | evaluate: true,
150 | if_return: true,
151 | join_vars: true,
152 | negate_iife: false // we need this for lazy v8
153 | },
154 | }),
155 |
156 |
157 |
158 | /**
159 | * Plugin: NormalModuleReplacementPlugin
160 | * Description: Replace resources that matches resourceRegExp with newResource
161 | *
162 | * See: http://webpack.github.io/docs/list-of-plugins.html#normalmodulereplacementplugin
163 | */
164 |
165 | new NormalModuleReplacementPlugin(
166 | /angular2-hmr/,
167 | helpers.root('client/config/empty.ts')
168 | ),
169 | new NormalModuleReplacementPlugin(
170 | /zone\.js(\\|\/)dist(\\|\/)long-stack-trace-zone/,
171 | helpers.root('client/config/empty.ts')
172 | ),
173 |
174 |
175 | /**
176 | * Plugin LoaderOptionsPlugin (experimental)
177 | *
178 | * See: https://gist.github.com/sokra/27b24881210b56bbaff7
179 | */
180 | new LoaderOptionsPlugin({
181 | minimize: true,
182 | debug: false,
183 | options: {
184 |
185 | /**
186 | * Html loader advanced options
187 | *
188 | * See: https://github.com/webpack/html-loader#advanced-options
189 | */
190 | // TODO: Need to workaround Angular 2's html syntax => #id [bind] (event) *ngFor
191 | htmlLoader: {
192 | minimize: true,
193 | removeAttributeQuotes: false,
194 | caseSensitive: true,
195 | customAttrSurround: [
196 | [/#/, /(?:)/],
197 | [/\*/, /(?:)/],
198 | [/\[?\(?/, /(?:)/]
199 | ],
200 | customAttrAssign: [/\)?\]?=/]
201 | },
202 |
203 | }
204 | }),
205 | ],
206 |
207 | /*
208 | * Include polyfills or mocks for various node stuff
209 | * Description: Node configuration
210 | *
211 | * See: https://webpack.github.io/docs/configuration.html#node
212 | */
213 | node: {
214 | global: true,
215 | crypto: 'empty',
216 | process: false,
217 | module: false,
218 | clearImmediate: false,
219 | setImmediate: false
220 | }
221 | })
222 |
--------------------------------------------------------------------------------
/client/custom-typings.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Custom Type Definitions
3 | * When including 3rd party modules you also need to include the type definition for the module
4 | * if they don't provide one within the module. You can try to install it with @types
5 |
6 | npm install @types/node
7 | npm install @types/lodash
8 |
9 | * If you can't find the type definition in the registry we can make an ambient/global definition in
10 | * this file for now. For example
11 |
12 | declare module "my-module" {
13 | export function doesSomething(value: string): string;
14 | }
15 |
16 | * If you are using a CommonJS module that is using module.exports then you will have to write your
17 | * types using export = yourObjectOrFunction with a namespace above it
18 | * notice how we have to create a namespace that is equal to the function we're assigning the export to
19 |
20 | declare module "jwt-decode" {
21 | function jwtDecode(token: string): any;
22 | namespace jwtDecode {}
23 | export = jwtDecode;
24 | }
25 |
26 | *
27 | * If you're prototying and you will fix the types later you can also declare it as type any
28 | *
29 |
30 | declare var assert: any;
31 | declare var _: any;
32 | declare var $: any;
33 |
34 | *
35 | * If you're importing a module that uses Node.js modules which are CommonJS you need to import as
36 | * in the files such as main.browser.ts or any file within app/
37 | *
38 |
39 | import * as _ from 'lodash'
40 |
41 | * You can include your type definitions in this file until you create one for the @types
42 | *
43 | */
44 |
45 | declare var $: any
46 |
47 | // support NodeJS modules without type definitions
48 | declare module "*"
49 |
50 | // Extra variables that live on Global that will be replaced by webpack DefinePlugin
51 | declare var ENV: string
52 | declare var HMR: boolean
53 | declare var System: SystemJS
54 |
55 | interface SystemJS {
56 | import: (path?: string) => Promise
57 | }
58 |
59 | interface GlobalEnvironment {
60 | ENV;
61 | HMR;
62 | SystemJS: SystemJS;
63 | System: SystemJS;
64 | }
65 |
66 | interface Es6PromiseLoader {
67 | (id: string): (exportName?: string) => Promise;
68 | }
69 |
70 | type FactoryEs6PromiseLoader = () => Es6PromiseLoader;
71 | type FactoryPromise = () => Promise;
72 |
73 | type AsyncRoutes = {
74 | [component: string]: Es6PromiseLoader |
75 | Function |
76 | FactoryEs6PromiseLoader |
77 | FactoryPromise
78 | };
79 |
80 |
81 | type IdleCallbacks = Es6PromiseLoader |
82 | Function |
83 | FactoryEs6PromiseLoader |
84 | FactoryPromise ;
85 |
86 | interface WebpackModule {
87 | hot: {
88 | data?: any,
89 | idle: any,
90 | accept(dependencies?: string | string[], callback?: (updatedDependencies?: any) => void): void;
91 | decline(deps?: any | string | string[]): void;
92 | dispose(callback?: (data?: any) => void): void;
93 | addDisposeHandler(callback?: (data?: any) => void): void;
94 | removeDisposeHandler(callback?: (data?: any) => void): void;
95 | check(autoApply?: any, callback?: (err?: Error, outdatedModules?: any[]) => void): void;
96 | apply(options?: any, callback?: (err?: Error, outdatedModules?: any[]) => void): void;
97 | status(callback?: (status?: string) => void): void | string;
98 | removeStatusHandler(callback?: (status?: string) => void): void;
99 | };
100 | }
101 |
102 |
103 | interface WebpackRequire {
104 | (id: string): any;
105 | (paths: string[], callback: (...modules: any[]) => void): void;
106 | ensure(ids: string[], callback: (req: WebpackRequire) => void, chunkName?: string): void;
107 | context(directory: string, useSubDirectories?: boolean, regExp?: RegExp): WebpackContext;
108 | }
109 |
110 | interface WebpackContext extends WebpackRequire {
111 | keys(): string[];
112 | }
113 |
114 | interface ErrorStackTraceLimit {
115 | stackTraceLimit: number;
116 | }
117 |
118 |
119 | // Extend typings
120 | interface NodeRequire extends WebpackRequire {}
121 | interface ErrorConstructor extends ErrorStackTraceLimit {}
122 | interface NodeRequireFunction extends Es6PromiseLoader {}
123 | interface NodeModule extends WebpackModule {}
124 | interface Global extends GlobalEnvironment {}
125 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <%= htmlWebpackPlugin.options.title %>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | <% if (webpackConfig.htmlElements.headTags) { %>
19 |
20 | <%= webpackConfig.htmlElements.headTags %>
21 | <% } %>
22 |
23 |
24 |
25 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/client/main.aot.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Angular bootstraping
3 | */
4 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
5 | import { decorateModuleRef } from './app/env'
6 | /*
7 | * App Module
8 | * our top level module that holds all of our components
9 | */
10 | import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'
11 |
12 |
13 | /*
14 | * Bootstrap our Angular app with a top level NgModule
15 | */
16 | export function main(): Promise {
17 | return platformBrowserDynamic()
18 | .bootstrapModule(AppModuleNgFactory)
19 | .then(decorateModuleRef)
20 | .catch(err => console.error(err))
21 | }
22 |
23 | export function bootstrapDomReady() {
24 | document.addEventListener('DOMContentLoaded', main)
25 | }
26 |
27 | bootstrapDomReady()
28 |
--------------------------------------------------------------------------------
/client/main.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Angular bootstraping
3 | */
4 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
5 | import { decorateModuleRef } from './app/env'
6 | import { bootloader } from '@angularclass/hmr'
7 | /*
8 | * App Module
9 | * our top level module that holds all of our components
10 | */
11 | import { AppModule } from './app'
12 |
13 | /*
14 | * Bootstrap our Angular app with a top level NgModule
15 | */
16 | export function main(): Promise {
17 | return platformBrowserDynamic()
18 | .bootstrapModule(AppModule)
19 | .then(decorateModuleRef)
20 | .catch(err => console.error(err))
21 | }
22 |
23 | // needed for hmr
24 | // in prod this is replace for document ready
25 | if (process.env.ENV === 'development') bootloader(main)
26 | else platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err))
27 |
28 |
--------------------------------------------------------------------------------
/client/polyfills.ts:
--------------------------------------------------------------------------------
1 | // TODO(gdi2290): switch to DLLs
2 |
3 | // Polyfills
4 |
5 | // import 'ie-shim'; // Internet Explorer 9 support
6 |
7 |
8 | // import 'core-js/es6';
9 | // Added parts of es6 which are necessary for your project or your browser support requirements.
10 | import 'core-js/es6/symbol'
11 | import 'core-js/es6/object'
12 | import 'core-js/es6/function'
13 | import 'core-js/es6/parse-int'
14 | import 'core-js/es6/parse-float'
15 | import 'core-js/es6/number'
16 | import 'core-js/es6/math'
17 | import 'core-js/es6/string'
18 | import 'core-js/es6/date'
19 | import 'core-js/es6/array'
20 | import 'core-js/es6/regexp'
21 | import 'core-js/es6/map'
22 | import 'core-js/es6/set'
23 | import 'core-js/es6/weak-map'
24 | import 'core-js/es6/weak-set'
25 | import 'core-js/es6/typed'
26 | import 'core-js/es6/reflect'
27 | // see issue https://github.com/AngularClass/angular2-webpack-starter/issues/709
28 | // import 'core-js/es6/promise'
29 |
30 | import 'core-js/es7/reflect'
31 | import 'zone.js/dist/zone'
32 |
33 |
34 | if ('production' === ENV) { // Production
35 |
36 |
37 | } else {
38 | // Development
39 |
40 | Error.stackTraceLimit = Infinity
41 |
42 | require('zone.js/dist/long-stack-trace-zone')
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/client/reducer/index.ts:
--------------------------------------------------------------------------------
1 | export * from './message'
2 |
--------------------------------------------------------------------------------
/client/reducer/message.ts:
--------------------------------------------------------------------------------
1 | import { ActionReducer, Action } from '@ngrx/store'
2 |
3 | export const MESSAGE_INIT = 'MESSAGE_INIT'
4 | export const MESSAGE_UPDATE = 'MESSAGE_UPDATE'
5 |
6 | export const message: ActionReducer = (state = [], action: Action) => {
7 | switch (action.type) {
8 | case MESSAGE_INIT:
9 | return action.payload
10 | case MESSAGE_UPDATE:
11 | return [
12 | ...state,
13 | ...action.payload
14 | ]
15 | default:
16 | return [...state]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/docker/dev.dockerfile:
--------------------------------------------------------------------------------
1 | FROM elaijuh/node
2 | ENV PROJECT_NAME famn
3 | MAINTAINER hjl
4 |
5 | RUN mkdir /famn
6 | WORKDIR /famn
7 |
8 | COPY package.json yarn.lock /famn/
9 | RUN yarn --ignore-optional && yarn cache clean
10 |
11 | EXPOSE 3030
12 |
13 | CMD yarn run start:hmr
14 |
--------------------------------------------------------------------------------
/docker/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | famn:
4 | build:
5 | context: ..
6 | dockerfile: ./docker/dev.dockerfile
7 | environment:
8 | - NODE_ENV=development
9 | - NODE_CONFIG_DIR=./app/config
10 | ports:
11 | - "3030:3030"
12 | volumes:
13 | - ..:/famn/
14 | - /famn/node_modules
15 | links:
16 | - mongo
17 | mongo:
18 | image: mongo:3.4
19 | ports:
20 | - "27017:27017" # for host connect
21 | volumes:
22 | - ~/docker/mongodb/log:/var/log/mongodb
23 | - ~/docker/data/db:/data/db
24 |
--------------------------------------------------------------------------------
/docker/docker-compose.prod.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | famn:
4 | build:
5 | context: ..
6 | dockerfile: ./docker/prod.dockerfile
7 | environment:
8 | NODE_ENV: production
9 | NODE_CONFIG_DIR: ./app/config
10 | ports:
11 | - "8080:8080"
12 | volumes:
13 | - ~/docker/famn/log:/var/log/famn
14 | links:
15 | - mongo
16 | mongo:
17 | image: mongo:3.4
18 | ports:
19 | - "27017:27017" # for host connect
20 | volumes:
21 | - ~/docker/mongodb/log:/var/log/mongodb
22 | - ~/docker/data/db:/data/db
23 |
--------------------------------------------------------------------------------
/docker/prod.dockerfile:
--------------------------------------------------------------------------------
1 | FROM elaijuh/node
2 | ENV PROJECT_NAME famn
3 | MAINTAINER hjl
4 |
5 | RUN mkdir /famn
6 | WORKDIR /famn
7 |
8 | COPY package.json yarn.lock /famn/
9 | RUN yarn --ignore-optional && yarn cache clean
10 |
11 | COPY . /famn
12 |
13 | EXPOSE 8080
14 |
15 | RUN yarn run build:client:prod
16 | RUN yarn run build:server:prod
17 | CMD sleep 5s && yarn run start:prod
18 |
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "famn",
3 | "version": "0.1.3",
4 | "description": "famn - angular2 application seed",
5 | "scripts": {
6 | "rimraf": "rimraf",
7 | "tslint": "tslint",
8 | "webpack": "webpack",
9 | "webpack-dev-server": "webpack-dev-server",
10 | "clean": "yarn cache clean && yarn run rimraf -- node_modules dist dll compiled",
11 | "clean:dist": "yarn run rimraf -- dist",
12 | "clean:dll": "yarn run rimraf -- dll",
13 | "clean:aot": "yarn run rimraf -- aot",
14 | "start": "yarn run start:hmr",
15 | "start:hmr": "NODE_ENV=development HMR=true nodemon --watch 'app/**/*.ts' --exec 'ts-node' server.ts",
16 | "start:prod": "NODE_ENV=production node ./dist/server/server.bundle.js",
17 | "build": "yarn run build:client:dev",
18 | "build:server": "yarn run build:server:prod",
19 | "prebuild:client:dev": "yarn run clean:dist",
20 | "prebuild:client:prod": "yarn run clean:dist",
21 | "prebuild:client:aot:prod": "yarn run clean:dist && yarn run clean:aot",
22 | "build:client:dev": "webpack --config ./client/config/webpack.dev.ts --progress --profile",
23 | "build:client:prod": "webpack --config ./client/config/webpack.prod.ts --progress --profile --bail",
24 | "build:client:aot:prod": "webpack --config ./client/config/webpack.prod.ts --progress --profile --bail",
25 | "build:server:prod": "webpack --config ./app/webpack/webpack.server.common.ts --progress --profile --bail",
26 | "lint": "yarn run tslint \"client/**/*.ts\""
27 | },
28 | "author": "Jiale Hu ",
29 | "license": "MIT",
30 | "dependencies": {
31 | "@angular/common": "2.4.8",
32 | "@angular/compiler": "2.4.8",
33 | "@angular/core": "2.4.8",
34 | "@angular/flex-layout": "2.0.0-rc.1",
35 | "@angular/forms": "2.4.8",
36 | "@angular/http": "2.4.8",
37 | "@angular/material": "2.0.0-beta.2",
38 | "@angular/platform-browser": "2.4.8",
39 | "@angular/platform-browser-dynamic": "2.4.8",
40 | "@angular/platform-server": "2.4.8",
41 | "@angular/router": "3.4.8",
42 | "@angularclass/form-validators": "^1.0.12",
43 | "@ngrx/core": "^1.2.0",
44 | "@ngrx/store": "^2.2.1",
45 | "ag-grid": "^8.1.1",
46 | "ag-grid-angular": "8.1.0",
47 | "angular-router-loader": "^0.4.0",
48 | "body-parser": "^1.15.2",
49 | "bunyan": "^1.8.3",
50 | "chalk": "^1.1.3",
51 | "compression": "^1.6.2",
52 | "core-js": "^2.4.1",
53 | "cors": "^2.8.0",
54 | "feathers": "~2.0.3",
55 | "feathers-authentication": "~1.1.1",
56 | "feathers-authentication-client": "~0.3.1",
57 | "feathers-authentication-jwt": "~0.3.1",
58 | "feathers-authentication-local": "~0.3.3",
59 | "feathers-configuration": "~0.4.1",
60 | "feathers-errors": "^2.5.0",
61 | "feathers-hooks": "^1.8.1",
62 | "feathers-mongoose": "^5.0.3",
63 | "feathers-permissions": "0.1.1",
64 | "feathers-rest": "^1.7.1",
65 | "feathers-socketio": "^1.5.2",
66 | "mongoose": "^4.8.6",
67 | "rxjs": "~5.2.0",
68 | "zone.js": "~0.7.8"
69 | },
70 | "devDependencies": {
71 | "@angular/compiler-cli": "2.4.8",
72 | "@angularclass/hmr": "1.2.2",
73 | "@angularclass/hmr-loader": "3.0.2",
74 | "@ngrx/store-devtools": "3.2.3",
75 | "@ngrx/store-log-monitor": "3.0.2",
76 | "@types/body-parser": "^0.0.34",
77 | "@types/bunyan": "^0.0.35",
78 | "@types/chalk": "^0.4.31",
79 | "@types/compression": "^0.0.33",
80 | "@types/core-js": "^0.9.35",
81 | "@types/cors": "0.0.31",
82 | "@types/mongoose": "^4.5.38",
83 | "@types/node": "^7.0.0",
84 | "add-asset-html-webpack-plugin": "^1.0.2",
85 | "angular2-template-loader": "^0.6.0",
86 | "assets-webpack-plugin": "^3.5.1",
87 | "awesome-typescript-loader": "~3.0.0-beta.18",
88 | "codelyzer": "~2.0.0-beta.4",
89 | "copy-webpack-plugin": "^4.0.0",
90 | "css-loader": "^0.26.0",
91 | "exports-loader": "^0.6.3",
92 | "expose-loader": "^0.7.1",
93 | "extract-text-webpack-plugin": "~2.0.0-rc.3",
94 | "file-loader": "^0.10.0",
95 | "html-webpack-plugin": "^2.28.0",
96 | "json-loader": "^0.5.4",
97 | "ng-router-loader": "^2.1.0",
98 | "ngc-webpack": "1.1.0",
99 | "node-sass": "^4.5.0",
100 | "nodemon": "^1.11.0",
101 | "optimize-js-plugin": "0.0.4",
102 | "raw-loader": "^0.5.1",
103 | "rimraf": "^2.5.2",
104 | "sass-loader": "^6.0.0",
105 | "script-ext-html-webpack-plugin": "^1.6.2",
106 | "style-loader": "^0.13.1",
107 | "to-string-loader": "^1.1.4",
108 | "ts-node": "^2.0.0",
109 | "tslib": "^1.5.0",
110 | "tslint": "~4.4.2",
111 | "tslint-loader": "^3.3.0",
112 | "typescript": "~2.1.6",
113 | "url-loader": "^0.5.7",
114 | "webpack": "2.2.0",
115 | "webpack-dev-middleware": "^1.10.0",
116 | "webpack-dev-server": "2.4.1",
117 | "webpack-dll-bundles-plugin": "^1.0.0-beta.5",
118 | "webpack-hot-middleware": "2.17.1",
119 | "webpack-merge": "~3.0.0"
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/process.yml:
--------------------------------------------------------------------------------
1 | apps:
2 | - script: dist/server/server.bundle.js
3 | name: app
4 | watch: false
5 | # instances: 4
6 | # exec_mode: cluster
7 |
--------------------------------------------------------------------------------
/server.ts:
--------------------------------------------------------------------------------
1 | import app from './app/app'
2 | const port = app.get('port')
3 | const server = app.listen(port)
4 |
5 | server.on('listening', () =>
6 | console.log(`Famn application started on ${app.get('host')}:${port}`)
7 | )
8 |
9 |
--------------------------------------------------------------------------------
/tsconfig.client.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "es2015",
5 | "moduleResolution": "node",
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "sourceMap": true,
10 | "noEmit": true,
11 | "noEmitHelpers": true,
12 | "importHelpers": true,
13 | "strictNullChecks": false,
14 | "lib": [
15 | "es2015",
16 | "dom"
17 | ],
18 | "typeRoots": [
19 | "node_modules/@types"
20 | ],
21 | "types": [
22 | "node"
23 | ]
24 | },
25 | "exclude": [
26 | "node_modules",
27 | "dist",
28 | "public",
29 | "client/**/*.spec.ts",
30 | "client/**/*.e2e.ts"
31 | ],
32 | "awesomeTypescriptLoaderOptions": {
33 | "forkChecker": true,
34 | "useWebpackText": true
35 | },
36 | "angularCompilerOptions": {
37 | "genDir": "./aot",
38 | "skipMetadataEmit": true
39 | },
40 | "compileOnSave": false,
41 | "buildOnSave": false,
42 | "atom": {
43 | "rewriteTsconfig": false
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "declaration": false,
7 | "removeComments": true,
8 | "noLib": false,
9 | "emitDecoratorMetadata": true,
10 | "experimentalDecorators": true,
11 | "sourceMap": true,
12 | "pretty": true,
13 | "allowUnreachableCode": false,
14 | "allowUnusedLabels": false,
15 | "noImplicitAny": false,
16 | "noImplicitReturns": true,
17 | "noImplicitUseStrict": false,
18 | "noFallthroughCasesInSwitch": true,
19 | "noEmitHelpers": true
20 | },
21 | "lib": [
22 | "dom",
23 | "es6"
24 | ],
25 | "typeRoots": [
26 | "node_modules/@types"
27 | ],
28 | "types": [
29 | "core-js",
30 | "jasmine",
31 | "node",
32 | "source-map",
33 | "uglify-js",
34 | "webpack",
35 | "mongoose"
36 | ],
37 | "exclude": [
38 | "client",
39 | "node_modules",
40 | "public",
41 | "dist"
42 | ],
43 | "awesomeTypescriptLoaderOptions": {
44 | "forkChecker": true,
45 | "useWebpackText": true
46 | },
47 | "compileOnSave": false,
48 | "buildOnSave": false,
49 | "atom": { "rewriteTsconfig": false }
50 | }
51 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | // "tslint:recommended"
4 | ],
5 | "rulesDirectory": [
6 | // "node_modules/codelyzer"
7 | ],
8 | "rules": {
9 | // Custom
10 | "trailing-comma": [false, {"multiline": "always", "singleline": "never"}],
11 | "interface-name": [false, "always-prefix"],
12 | // Angular 2
13 | "component-class-suffix": true,
14 | // "component-selector": [true, "element", "my", "kebab-case"],
15 | "directive-class-suffix": true,
16 | // "directive-selector": [true, "attribute", "my", "camelCase"],
17 | "import-destructuring-spacing": true,
18 | "invoke-injectable": true,
19 | "no-access-missing-member": true,
20 | "no-attribute-parameter-decorator": true,
21 | "no-forward-ref": true,
22 | "no-input-rename": true,
23 | "no-output-rename": true,
24 | "pipe-naming": [true, "camelCase", "my"],
25 | "templates-use-public": true,
26 | "use-host-property-decorator": true,
27 | "use-input-property-decorator": true,
28 | "use-life-cycle-interface": true,
29 | "use-output-property-decorator": true,
30 | "use-pipe-transform-interface": true,
31 | // General
32 | "no-console": [true,
33 | "time",
34 | "timeEnd",
35 | "trace"
36 | ],
37 | "max-line-length": [
38 | true,
39 | 100
40 | ],
41 | "no-string-literal": false,
42 | "no-use-before-declare": true,
43 | "object-literal-sort-keys": false,
44 | "ordered-imports": false,
45 | "quotemark": [
46 | true,
47 | "single",
48 | "avoid-escape"
49 | ],
50 | "semicolon": [true, "never"],
51 | "variable-name": [
52 | true,
53 | "allow-leading-underscore",
54 | "allow-pascal-case",
55 | "ban-keywords",
56 | "check-format"
57 | ]
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Look in `./config` folder for `webpack.*.config.js`
2 | switch (process.env.NODE_ENV) {
3 | case 'prod':
4 | case 'production':
5 | module.exports = require('./client/config/webpack.prod');
6 | break;
7 | case 'test':
8 | case 'testing':
9 | module.exports = require('./client/config/webpack.test');
10 | break;
11 | case 'dev':
12 | case 'development':
13 | default:
14 | module.exports = require('./client/config/webpack.dev');
15 | }
16 |
--------------------------------------------------------------------------------