├── .DS_Store ├── .gitignore ├── animating-child-route ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── logo.png │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── Modal.vue │ │ ├── icons │ │ │ ├── Close.vue │ │ │ └── Delete.vue │ │ └── pages │ │ │ └── game │ │ │ ├── List.vue │ │ │ ├── Single.vue │ │ │ └── rule │ │ │ ├── List.vue │ │ │ └── Single.vue │ ├── data │ │ └── games.js │ ├── main.js │ ├── router │ │ └── index.js │ └── styles │ │ ├── _colors.scss │ │ ├── base.scss │ │ └── normalize.scss ├── static │ └── .gitkeep └── yarn.lock ├── docs ├── animating-child-route │ ├── css │ │ ├── app.5c2176ebe79045b522ab63a9a5ec9fdd.css │ │ └── app.5c2176ebe79045b522ab63a9a5ec9fdd.css.map │ ├── index.html │ └── js │ │ ├── app.b2e513a43e7dfc676b6b.js │ │ ├── app.b2e513a43e7dfc676b6b.js.map │ │ ├── manifest.1b8b88fb7a426a6d3f67.js │ │ ├── manifest.1b8b88fb7a426a6d3f67.js.map │ │ ├── vendor.be70c74316613424bdf6.js │ │ └── vendor.be70c74316613424bdf6.js.map ├── index.html ├── sidebar-dynamic │ ├── index.html │ └── static │ │ ├── css │ │ ├── app.a1b9c94bdc470f5ed9184569e8cd64ea.css │ │ └── app.a1b9c94bdc470f5ed9184569e8cd64ea.css.map │ │ └── js │ │ ├── app.cc4efbd447cb00403ba7.js │ │ ├── app.cc4efbd447cb00403ba7.js.map │ │ ├── manifest.ecfa1adc4a7519c26d6b.js │ │ ├── manifest.ecfa1adc4a7519c26d6b.js.map │ │ ├── vendor.59e1447691d6f3a63918.js │ │ └── vendor.59e1447691d6f3a63918.js.map └── sidebar │ ├── index.html │ └── static │ ├── css │ ├── app.e439c225a7a4e3d818fb42e3f740d862.css │ └── app.e439c225a7a4e3d818fb42e3f740d862.css.map │ └── js │ ├── app.7e8ea3700ad2708b65ba.js │ ├── app.7e8ea3700ad2708b65ba.js.map │ ├── manifest.0dc805fcf281e9020471.js │ ├── manifest.0dc805fcf281e9020471.js.map │ ├── vendor.59e1447691d6f3a63918.js │ └── vendor.59e1447691d6f3a63918.js.map ├── prisma-auth0 └── server │ ├── .gitignore │ ├── .graphqlconfig.yml │ ├── README.md │ ├── database │ ├── datamodel.graphql │ ├── prisma.yml │ └── seed.graphql │ ├── package.json │ ├── src │ ├── generated │ │ └── prisma.graphql │ ├── index.js │ ├── resolvers │ │ ├── AuthPayload.js │ │ ├── Mutation │ │ │ ├── auth.js │ │ │ └── post.js │ │ ├── Query.js │ │ └── index.js │ ├── schema.graphql │ └── utils.js │ └── yarn.lock ├── sidebar-dynamic ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── logo.png │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ ├── webpack.prod.conf.js │ └── webpack.test.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── components │ │ ├── addForm.vue │ │ ├── searchForm.vue │ │ ├── sidebar.vue │ │ └── sidebarToggle.vue │ ├── icons │ │ ├── add.vue │ │ └── search.vue │ ├── main.js │ └── store │ │ ├── index.js │ │ ├── modules │ │ └── ui.js │ │ └── mutation-types.js ├── static │ └── .gitkeep └── yarn.lock ├── sidebar ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── logo.png │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ ├── webpack.prod.conf.js │ └── webpack.test.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── sidebar.vue │ │ └── sidebarToggle.vue │ ├── main.js │ └── store │ │ ├── index.js │ │ ├── modules │ │ └── ui.js │ │ └── mutation-types.js ├── static │ └── .gitkeep └── yarn.lock ├── thumbnail-creator ├── .serverless │ ├── cloudformation-template-create-stack.json │ ├── cloudformation-template-update-stack.json │ ├── serverless-state.json │ └── thumbnail-creator.zip ├── README.md ├── client │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .postcssrc.js │ ├── README.md │ ├── build │ │ ├── build.js │ │ ├── check-versions.js │ │ ├── logo.png │ │ ├── utils.js │ │ ├── vue-loader.conf.js │ │ ├── webpack.base.conf.js │ │ ├── webpack.dev.conf.js │ │ └── webpack.prod.conf.js │ ├── config │ │ ├── dev.env.js │ │ ├── index.js │ │ └── prod.env.js │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── logo.png │ │ ├── aws.js │ │ ├── components │ │ │ ├── Home.vue │ │ │ ├── appHeader.vue │ │ │ ├── list.vue │ │ │ ├── upload.vue │ │ │ └── uploadForm.vue │ │ ├── main.js │ │ └── router │ │ │ └── index.js │ └── static │ │ └── .gitkeep ├── handlers │ ├── test.json │ └── transform.js ├── package.json ├── serverless.yml └── sharp │ ├── Dockerfile │ ├── build.sh │ └── tarballs │ └── sharp-0.18.4-aws-lambda-linux-x64-node-6.10.1.tar.gz └── video-colors ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── README.md ├── build ├── build.js ├── check-versions.js ├── logo.png ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── index.html ├── package.json ├── src ├── App.vue ├── assets │ ├── logo.png │ └── test.mp4 ├── chart.vue ├── main.js └── worker.js └── static └── .gitkeep /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/config/development.json 2 | **/config/production.json 3 | **/config/client.json 4 | **/dist 5 | node_modules 6 | -------------------------------------------------------------------------------- /animating-child-route/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"] 12 | } 13 | -------------------------------------------------------------------------------- /animating-child-route/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /animating-child-route/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | -------------------------------------------------------------------------------- /animating-child-route/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parserOptions: { 6 | parser: 'babel-eslint' 7 | }, 8 | env: { 9 | browser: true, 10 | }, 11 | extends: [ 12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 14 | 'plugin:vue/essential', 15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 16 | 'standard' 17 | ], 18 | // required to lint *.vue files 19 | plugins: [ 20 | 'vue' 21 | ], 22 | // add your custom rules here 23 | rules: { 24 | // allow async-await 25 | 'generator-star-spacing': 'off', 26 | // allow debugger during development 27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /animating-child-route/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /animating-child-route/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /animating-child-route/README.md: -------------------------------------------------------------------------------- 1 | # animating-child-route 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /animating-child-route/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /animating-child-route/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /animating-child-route/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/animating-child-route/build/logo.png -------------------------------------------------------------------------------- /animating-child-route/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const packageConfig = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | 15 | exports.cssLoaders = function (options) { 16 | options = options || {} 17 | 18 | const cssLoader = { 19 | loader: 'css-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | } 24 | 25 | const postcssLoader = { 26 | loader: 'postcss-loader', 27 | options: { 28 | sourceMap: options.sourceMap 29 | } 30 | } 31 | 32 | // generate loader string to be used with extract text plugin 33 | function generateLoaders (loader, loaderOptions) { 34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 35 | 36 | if (loader) { 37 | loaders.push({ 38 | loader: loader + '-loader', 39 | options: Object.assign({}, loaderOptions, { 40 | sourceMap: options.sourceMap 41 | }) 42 | }) 43 | } 44 | 45 | // Extract CSS when that option is specified 46 | // (which is the case during production build) 47 | if (options.extract) { 48 | return ExtractTextPlugin.extract({ 49 | use: loaders, 50 | fallback: 'vue-style-loader' 51 | }) 52 | } else { 53 | return ['vue-style-loader'].concat(loaders) 54 | } 55 | } 56 | 57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 58 | return { 59 | css: generateLoaders(), 60 | postcss: generateLoaders(), 61 | less: generateLoaders('less'), 62 | sass: generateLoaders('sass', { indentedSyntax: true }), 63 | scss: generateLoaders('sass'), 64 | stylus: generateLoaders('stylus'), 65 | styl: generateLoaders('stylus') 66 | } 67 | } 68 | 69 | // Generate loaders for standalone style files (outside of .vue) 70 | exports.styleLoaders = function (options) { 71 | const output = [] 72 | const loaders = exports.cssLoaders(options) 73 | 74 | for (const extension in loaders) { 75 | const loader = loaders[extension] 76 | output.push({ 77 | test: new RegExp('\\.' + extension + '$'), 78 | use: loader 79 | }) 80 | } 81 | 82 | return output 83 | } 84 | 85 | exports.createNotifierCallback = () => { 86 | const notifier = require('node-notifier') 87 | 88 | return (severity, errors) => { 89 | if (severity !== 'error') return 90 | 91 | const error = errors[0] 92 | const filename = error.file && error.file.split('!').pop() 93 | 94 | notifier.notify({ 95 | title: packageConfig.name, 96 | message: severity + ': ' + error.name, 97 | subtitle: filename || '', 98 | icon: path.join(__dirname, 'logo.png') 99 | }) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /animating-child-route/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /animating-child-route/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | const createLintingRule = () => ({ 12 | test: /\.(js|vue)$/, 13 | loader: 'eslint-loader', 14 | enforce: 'pre', 15 | include: [resolve('src'), resolve('test')], 16 | options: { 17 | formatter: require('eslint-friendly-formatter'), 18 | emitWarning: !config.dev.showEslintErrorsInOverlay 19 | } 20 | }) 21 | 22 | module.exports = { 23 | context: path.resolve(__dirname, '../'), 24 | entry: { 25 | app: './src/main.js' 26 | }, 27 | output: { 28 | path: config.build.assetsRoot, 29 | filename: '[name].js', 30 | publicPath: process.env.NODE_ENV === 'production' 31 | ? config.build.assetsPublicPath 32 | : config.dev.assetsPublicPath 33 | }, 34 | resolve: { 35 | extensions: ['.js', '.vue', '.json'], 36 | alias: { 37 | 'vue$': 'vue/dist/vue.esm.js', 38 | '@': resolve('src'), 39 | } 40 | }, 41 | module: { 42 | rules: [ 43 | ...(config.dev.useEslint ? [createLintingRule()] : []), 44 | { 45 | test: /\.vue$/, 46 | loader: 'vue-loader', 47 | options: vueLoaderConfig 48 | }, 49 | { 50 | test: /\.js$/, 51 | loader: 'babel-loader', 52 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] 53 | }, 54 | { 55 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 56 | loader: 'url-loader', 57 | options: { 58 | limit: 10000, 59 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 60 | } 61 | }, 62 | { 63 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 64 | loader: 'url-loader', 65 | options: { 66 | limit: 10000, 67 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 68 | } 69 | }, 70 | { 71 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 72 | loader: 'url-loader', 73 | options: { 74 | limit: 10000, 75 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 76 | } 77 | } 78 | ] 79 | }, 80 | node: { 81 | // prevent webpack from injecting useless setImmediate polyfill because Vue 82 | // source contains it (although only uses it if it's native). 83 | setImmediate: false, 84 | // prevent webpack from injecting mocks to Node native modules 85 | // that does not make sense for the client 86 | dgram: 'empty', 87 | fs: 'empty', 88 | net: 'empty', 89 | tls: 'empty', 90 | child_process: 'empty' 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /animating-child-route/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const path = require('path') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 11 | const portfinder = require('portfinder') 12 | 13 | const HOST = process.env.HOST 14 | const PORT = process.env.PORT && Number(process.env.PORT) 15 | 16 | const devWebpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 19 | }, 20 | // cheap-module-eval-source-map is faster for development 21 | devtool: config.dev.devtool, 22 | 23 | // these devServer options should be customized in /config/index.js 24 | devServer: { 25 | clientLogLevel: 'warning', 26 | historyApiFallback: { 27 | rewrites: [ 28 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, 29 | ], 30 | }, 31 | hot: true, 32 | contentBase: false, // since we use CopyWebpackPlugin. 33 | compress: true, 34 | host: HOST || config.dev.host, 35 | port: PORT || config.dev.port, 36 | open: config.dev.autoOpenBrowser, 37 | overlay: config.dev.errorOverlay 38 | ? { warnings: false, errors: true } 39 | : false, 40 | publicPath: config.dev.assetsPublicPath, 41 | proxy: config.dev.proxyTable, 42 | quiet: true, // necessary for FriendlyErrorsPlugin 43 | watchOptions: { 44 | poll: config.dev.poll, 45 | } 46 | }, 47 | plugins: [ 48 | new webpack.DefinePlugin({ 49 | 'process.env': require('../config/dev.env') 50 | }), 51 | new webpack.HotModuleReplacementPlugin(), 52 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 53 | new webpack.NoEmitOnErrorsPlugin(), 54 | // https://github.com/ampedandwired/html-webpack-plugin 55 | new HtmlWebpackPlugin({ 56 | filename: 'index.html', 57 | template: 'index.html', 58 | inject: true 59 | }), 60 | // copy custom static assets 61 | new CopyWebpackPlugin([ 62 | { 63 | from: path.resolve(__dirname, '../static'), 64 | to: config.dev.assetsSubDirectory, 65 | ignore: ['.*'] 66 | } 67 | ]) 68 | ] 69 | }) 70 | 71 | module.exports = new Promise((resolve, reject) => { 72 | portfinder.basePort = process.env.PORT || config.dev.port 73 | portfinder.getPort((err, port) => { 74 | if (err) { 75 | reject(err) 76 | } else { 77 | // publish the new Port, necessary for e2e tests 78 | process.env.PORT = port 79 | // add port to devServer config 80 | devWebpackConfig.devServer.port = port 81 | 82 | // Add FriendlyErrorsPlugin 83 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 84 | compilationSuccessInfo: { 85 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 86 | }, 87 | onErrors: config.dev.notifyOnErrors 88 | ? utils.createNotifierCallback() 89 | : undefined 90 | })) 91 | 92 | resolve(devWebpackConfig) 93 | } 94 | }) 95 | }) 96 | -------------------------------------------------------------------------------- /animating-child-route/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /animating-child-route/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'cheap-module-eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | cssSourceMap: true 44 | }, 45 | 46 | build: { 47 | // Template for index.html 48 | index: path.resolve(__dirname, '../docs/index.html'), 49 | 50 | // Paths 51 | assetsRoot: path.resolve(__dirname, '../docs'), 52 | assetsSubDirectory: '', 53 | assetsPublicPath: '', 54 | 55 | /** 56 | * Source Maps 57 | */ 58 | 59 | productionSourceMap: true, 60 | // https://webpack.js.org/configuration/devtool/#production 61 | devtool: '#source-map', 62 | 63 | // Gzip off by default as many popular static hosts such as 64 | // Surge or Netlify already gzip all static assets for you. 65 | // Before setting to `true`, make sure to: 66 | // npm install --save-dev compression-webpack-plugin 67 | productionGzip: false, 68 | productionGzipExtensions: ['js', 'css'], 69 | 70 | // Run the build command with an extra argument to 71 | // View the bundle analyzer report after build finishes: 72 | // `npm run build --report` 73 | // Set to `true` or `false` to always turn it on or off 74 | bundleAnalyzerReport: process.env.npm_config_report 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /animating-child-route/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /animating-child-route/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | animating-child-route 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /animating-child-route/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "animating-child-route", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "lint": "eslint --ext .js,.vue src", 11 | "build": "node build/build.js" 12 | }, 13 | "dependencies": { 14 | "gsap": "^1.20.3", 15 | "node-sass": "^4.7.2", 16 | "sass-loader": "^6.0.6", 17 | "vue": "^2.5.2", 18 | "vue-router": "^3.0.1" 19 | }, 20 | "devDependencies": { 21 | "autoprefixer": "^7.1.2", 22 | "babel-core": "^6.22.1", 23 | "babel-eslint": "^8.2.1", 24 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 25 | "babel-loader": "^7.1.1", 26 | "babel-plugin-syntax-jsx": "^6.18.0", 27 | "babel-plugin-transform-runtime": "^6.22.0", 28 | "babel-plugin-transform-vue-jsx": "^3.5.0", 29 | "babel-preset-env": "^1.3.2", 30 | "babel-preset-stage-2": "^6.22.0", 31 | "chalk": "^2.0.1", 32 | "copy-webpack-plugin": "^4.0.1", 33 | "css-loader": "^0.28.0", 34 | "eslint": "^4.15.0", 35 | "eslint-config-standard": "^10.2.1", 36 | "eslint-friendly-formatter": "^3.0.0", 37 | "eslint-loader": "^1.7.1", 38 | "eslint-plugin-import": "^2.7.0", 39 | "eslint-plugin-node": "^5.2.0", 40 | "eslint-plugin-promise": "^3.4.0", 41 | "eslint-plugin-standard": "^3.0.1", 42 | "eslint-plugin-vue": "^4.0.0", 43 | "extract-text-webpack-plugin": "^3.0.0", 44 | "file-loader": "^1.1.4", 45 | "friendly-errors-webpack-plugin": "^1.6.1", 46 | "html-webpack-plugin": "^2.30.1", 47 | "node-notifier": "^5.1.2", 48 | "optimize-css-assets-webpack-plugin": "^3.2.0", 49 | "ora": "^1.2.0", 50 | "portfinder": "^1.0.13", 51 | "postcss-import": "^11.0.0", 52 | "postcss-loader": "^2.0.8", 53 | "postcss-url": "^7.2.1", 54 | "rimraf": "^2.6.0", 55 | "semver": "^5.3.0", 56 | "shelljs": "^0.7.6", 57 | "uglifyjs-webpack-plugin": "^1.1.1", 58 | "url-loader": "^0.5.8", 59 | "vue-loader": "^13.3.0", 60 | "vue-style-loader": "^3.0.1", 61 | "vue-template-compiler": "^2.5.2", 62 | "webpack": "^3.6.0", 63 | "webpack-bundle-analyzer": "^2.9.0", 64 | "webpack-dev-server": "^2.9.1", 65 | "webpack-merge": "^4.1.0" 66 | }, 67 | "engines": { 68 | "node": ">= 6.0.0", 69 | "npm": ">= 3.0.0" 70 | }, 71 | "browserslist": [ 72 | "> 1%", 73 | "last 2 versions", 74 | "not ie <= 8" 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /animating-child-route/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 28 | -------------------------------------------------------------------------------- /animating-child-route/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/animating-child-route/src/assets/logo.png -------------------------------------------------------------------------------- /animating-child-route/src/components/Modal.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 47 | 48 | 89 | -------------------------------------------------------------------------------- /animating-child-route/src/components/icons/Close.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /animating-child-route/src/components/icons/Delete.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 17 | -------------------------------------------------------------------------------- /animating-child-route/src/components/pages/game/List.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 27 | 28 | 79 | -------------------------------------------------------------------------------- /animating-child-route/src/components/pages/game/Single.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 42 | 43 | 67 | -------------------------------------------------------------------------------- /animating-child-route/src/components/pages/game/rule/List.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 31 | 32 | 69 | -------------------------------------------------------------------------------- /animating-child-route/src/components/pages/game/rule/Single.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 31 | 32 | 82 | -------------------------------------------------------------------------------- /animating-child-route/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | 7 | Vue.config.productionTip = false 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#app', 12 | router, 13 | components: { App }, 14 | template: '' 15 | }) 16 | -------------------------------------------------------------------------------- /animating-child-route/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import GameList from '@/components/pages/game/List.vue' 4 | import GameSingle from '@/components/pages/game/Single.vue' 5 | import RuleList from '@/components/pages/game/rule/List.vue' 6 | import RuleSingle from '@/components/pages/game/rule/Single.vue' 7 | 8 | Vue.use(Router) 9 | 10 | export default new Router({ 11 | routes: [ 12 | { 13 | path: '/', 14 | component: GameList 15 | }, 16 | { 17 | path: '/game/:id', 18 | name: 'Game', 19 | component: GameSingle, 20 | children: [ 21 | { 22 | path: 'rules', 23 | name: 'Game Rules', 24 | components: { 25 | page: RuleList 26 | }, 27 | meta: { 28 | showModal: false 29 | } 30 | }, 31 | { 32 | path: 'rules/:ruleId', 33 | name: 'Game Rule', 34 | components: { 35 | page: RuleList, 36 | rule: RuleSingle 37 | }, 38 | meta: { 39 | showModal: true 40 | } 41 | } 42 | ] 43 | } 44 | ] 45 | }) 46 | -------------------------------------------------------------------------------- /animating-child-route/src/styles/_colors.scss: -------------------------------------------------------------------------------- 1 | $primary: #f26f4d; 2 | $secondary: #8471b3; 3 | 4 | $page-gradient: linear-gradient(-200deg, $primary 40%, adjust-hue($primary, -5%) 80%); 5 | $profile-gradient: linear-gradient(180deg, $secondary 0%, adjust-hue($secondary, -10%) 100%); 6 | $submit-gradient: linear-gradient(-200deg, $secondary 0%, adjust-hue($secondary, -40%) 100%); -------------------------------------------------------------------------------- /animating-child-route/src/styles/base.scss: -------------------------------------------------------------------------------- 1 | @import "./_colors.scss"; 2 | 3 | .page{ 4 | background-image: $page-gradient; 5 | min-height: 100vh; 6 | padding: 1rem; 7 | } -------------------------------------------------------------------------------- /animating-child-route/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/animating-child-route/static/.gitkeep -------------------------------------------------------------------------------- /docs/animating-child-route/css/app.5c2176ebe79045b522ab63a9a5ec9fdd.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Rubik:400,700); 2 | /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}.page{background-image:linear-gradient(-200deg,#f26f4d 40%,#f2614d 80%);min-height:100vh;padding:1rem}#app{font-family:Rubik,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*{box-sizing:border-box}.body[data-v-9555ea32],.page[data-v-9555ea32]{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.body[data-v-9555ea32]{padding:0;-ms-flex-flow:column;flex-flow:column;background-color:#fff;padding:2rem}.title[data-v-9555ea32]{font-size:3rem;font-weight:100}.list[data-v-9555ea32]{list-style:none;padding:0;margin:0}.list-item[data-v-9555ea32]:not(:last-of-type){margin-bottom:.5rem}.link[data-v-9555ea32]{background-color:#f26f4d;display:block;padding:1rem;color:#fff;font-size:1.5rem;text-decoration:none;border-radius:3px}.link[data-v-9555ea32]:hover{background-color:#8471b3}.page[data-v-7f60e7da]{padding:0}.header[data-v-7f60e7da]{background-color:#fff;padding:1rem;text-align:center}.wrapper[data-v-7f60e7da]{max-width:800px;margin:0 auto}.title[data-v-7f60e7da]{font-size:3rem;font-weight:100;color:#f26f4d}.modal[data-v-632b7e47]{position:fixed;top:0;left:0;height:100vh;width:100vw;background-color:rgba(0,0,0,.8);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.inner[data-v-632b7e47]{background-color:#fff;width:800px;position:relative}.close-button[data-v-632b7e47]{position:absolute;top:-40px;right:0;border:0;height:40px;width:40px;background-color:#f2f2f2;cursor:pointer;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.close-button svg[data-v-632b7e47]{width:30px;height:30px}.title[data-v-6652bc69]{font-size:2rem;color:#fff;font-weight:100;margin:2rem 0}.list[data-v-6652bc69]{list-style:none;padding:0;margin:0}.list-item[data-v-6652bc69]:not(:last-of-type){margin-bottom:.5rem}.link[data-v-6652bc69]{display:block;padding:1rem;color:#f26f4d;font-size:1.2rem;text-decoration:none;border-radius:3px;background-color:#fff}.link[data-v-6652bc69]:hover{background-color:#8471b3;color:#fff}.rule[data-v-4436bdc1]{height:100%;background-color:#f2f2f2;position:relative}.body[data-v-4436bdc1]{padding:2rem;background-color:#fff}.text[data-v-4436bdc1]{margin:0;font-size:1.5rem;line-height:1.5}.menu[data-v-4436bdc1]{position:absolute;bottom:-1rem;left:0}.menu ul[data-v-4436bdc1]{list-style:none;padding:0;margin:0}.menu button[data-v-4436bdc1]{position:absolute;bottom:-4rem;left:0;border:0;height:4rem;width:4rem;background-color:#8471b3;cursor:pointer;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.menu button svg[data-v-4436bdc1]{width:30px;height:30px} 3 | /*# sourceMappingURL=app.5c2176ebe79045b522ab63a9a5ec9fdd.css.map */ -------------------------------------------------------------------------------- /docs/animating-child-route/index.html: -------------------------------------------------------------------------------- 1 | animating-child-route
-------------------------------------------------------------------------------- /docs/animating-child-route/js/manifest.1b8b88fb7a426a6d3f67.js: -------------------------------------------------------------------------------- 1 | !function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,u){for(var a,i,f,s=0,l=[];s 2 | 3 | 4 | 5 | 6 | 7 | Vue Tutorial Examples 8 | 9 | 45 | 46 | 47 | 48 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/sidebar-dynamic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Dynamic Sidebar 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/sidebar-dynamic/static/css/app.a1b9c94bdc470f5ed9184569e8cd64ea.css: -------------------------------------------------------------------------------- 1 | :root{--accent-color:#ffcb08;--primary-color:#820263;--dark-color:#2e294e}*{box-sizing:border-box}._1yQEW-OB4Ybyf_vE6oWyGO_1{position:fixed;left:0;top:0;height:100vh;width:100vw;background-color:var(--primary-color)}.d_6wpGL-HDubyTBE0M-h8_1{position:fixed;right:1rem;bottom:1rem;display:-ms-flexbox;display:flex}._1Akv3QSGkfLjHLmQBua5gq_0{position:fixed;right:0;top:0;width:300px;height:100vh;max-width:90vw;background-color:var(--accent-color);padding:1rem}._2lbLj0f9KsKJTS3AY46M7w_0{padding:0;height:50px;width:50px;border:3px solid transparent;border-radius:50%;background-color:transparent;color:var(--dark-color);cursor:pointer;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;line-height:0;transition:transform .3s ease-out,border-color .3s ease-out}._2lbLj0f9KsKJTS3AY46M7w_0 svg{height:100%;width:100%;fill:var(--accent-color);transition:fill .3s ease-out}._2lbLj0f9KsKJTS3AY46M7w_0:focus{outline:none;border-color:var(--accent-color)}.n02dqwlexV56EeqjpzyEx_0{transform:rotate(45deg)}.n02dqwlexV56EeqjpzyEx_0 svg{fill:var(--primary-color)}.n02dqwlexV56EeqjpzyEx_0:focus{border-color:var(--primary-color)}._3-2e6nsGqNdlimbojUKT1s_0,.pugt3ynvQ0eZJzxl6baou_0{font-size:3rem;color:#fff;font-family:roboto} 2 | /*# sourceMappingURL=app.a1b9c94bdc470f5ed9184569e8cd64ea.css.map */ -------------------------------------------------------------------------------- /docs/sidebar-dynamic/static/css/app.a1b9c94bdc470f5ed9184569e8cd64ea.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["app.a1b9c94bdc470f5ed9184569e8cd64ea.css"],"names":[],"mappings":"AACA,MACE,uBAAwB,AACxB,wBAAyB,AACzB,oBAAsB,CACvB,AACD,EAEU,qBAAuB,CAChC,AAGD,2BACE,eAAgB,AAChB,OAAQ,AACR,MAAO,AACP,aAAc,AACd,YAAa,AACb,qCAAuC,CACxC,AACD,yBACE,eAAgB,AAChB,WAAY,AACZ,YAAa,AAEb,oBAAqB,AACrB,YAAc,CACf,AAED,2BACE,eAAgB,AAChB,QAAS,AACT,MAAO,AACP,YAAa,AACb,aAAc,AACd,eAAgB,AAChB,qCAAsC,AACtC,YAAc,CACf,AAED,2BACE,UAAW,AACX,YAAa,AACb,WAAY,AACZ,6BAA8B,AAC9B,kBAAmB,AACnB,6BAA8B,AAC9B,wBAAyB,AACzB,eAAgB,AAEhB,oBAAqB,AACrB,aAAc,AAEV,sBAAuB,AACnB,mBAAoB,AAExB,qBAAsB,AAClB,uBAAwB,AAChC,cAAe,AAGf,2DAAkE,CAEnE,AACD,+BACE,YAAa,AACb,WAAY,AACZ,yBAA0B,AAE1B,4BAAgC,CACjC,AACD,iCACE,aAAc,AACd,gCAAkC,CACnC,AACD,yBAEU,uBAAyB,CAClC,AACD,6BACE,yBAA2B,CAC5B,AACD,+BACE,iCAAmC,CACpC,AASD,oDACE,eAAgB,AAChB,WAAa,AACb,kBAAsB,CACvB","file":"app.a1b9c94bdc470f5ed9184569e8cd64ea.css","sourcesContent":["\n:root{\n --accent-color: #FFCB08;\n --primary-color: #820263;\n --dark-color: #2E294E;\n}\n*{\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n\n._1yQEW-OB4Ybyf_vE6oWyGO_1{\n position: fixed;\n left: 0;\n top: 0;\n height: 100vh;\n width: 100vw;\n background-color: var(--primary-color);\n}\n.d_6wpGL-HDubyTBE0M-h8_1{\n position: fixed;\n right: 1rem;\n bottom: 1rem;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n}\n\n._1Akv3QSGkfLjHLmQBua5gq_0{\n position: fixed;\n right: 0;\n top: 0;\n width: 300px;\n height: 100vh;\n max-width: 90vw;\n background-color: var(--accent-color);\n padding: 1rem;\n}\n\n._2lbLj0f9KsKJTS3AY46M7w_0{\n padding: 0;\n height: 50px;\n width: 50px;\n border: 3px solid transparent;\n border-radius: 50%;\n background-color: transparent;\n color: var(--dark-color);\n cursor: pointer;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n line-height: 0;\n -webkit-transition: border-color 300ms ease-out, -webkit-transform 300ms ease-out;\n transition: border-color 300ms ease-out, -webkit-transform 300ms ease-out;\n transition: transform 300ms ease-out, border-color 300ms ease-out;\n transition: transform 300ms ease-out, border-color 300ms ease-out, -webkit-transform 300ms ease-out;\n}\n._2lbLj0f9KsKJTS3AY46M7w_0 svg{\n height: 100%;\n width: 100%;\n fill: var(--accent-color);\n -webkit-transition: fill 300ms ease-out;\n transition: fill 300ms ease-out;\n}\n._2lbLj0f9KsKJTS3AY46M7w_0:focus{\n outline: none;\n border-color: var(--accent-color);\n}\n.n02dqwlexV56EeqjpzyEx_0{\n -webkit-transform: rotate(45deg);\n transform: rotate(45deg);\n}\n.n02dqwlexV56EeqjpzyEx_0 svg{\n fill: var(--primary-color);\n}\n.n02dqwlexV56EeqjpzyEx_0:focus{\n border-color: var(--primary-color);\n}\n\n\n.pugt3ynvQ0eZJzxl6baou_0{\n font-size: 3rem;\n color: white;\n font-family: 'roboto';\n}\n\n._3-2e6nsGqNdlimbojUKT1s_0{\n font-size: 3rem;\n color: white;\n font-family: 'roboto';\n}\n"]} -------------------------------------------------------------------------------- /docs/sidebar-dynamic/static/js/app.cc4efbd447cb00403ba7.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],{"1GX7":function(e,t){e.exports={button:"_2lbLj0f9KsKJTS3AY46M7w_0",active:"n02dqwlexV56EeqjpzyEx_0"}},"32HJ":function(e,t){e.exports={title:"_3-2e6nsGqNdlimbojUKT1s_0"}},"7jBf":function(e,t){e.exports={container:"_1yQEW-OB4Ybyf_vE6oWyGO_1",toggles:"d_6wpGL-HDubyTBE0M-h8_1"}},EZew:function(e,t){e.exports={title:"pugt3ynvQ0eZJzxl6baou_0"}},NHnr:function(e,t,n){"use strict";function s(e){this.$style=n("wpMw")}function r(e){this.$style=n("1GX7")}function o(e){this.$style=n("EZew")}function i(e){this.$style=n("32HJ")}function a(e){n("z8r5"),this.$style=n("7jBf")}Object.defineProperty(t,"__esModule",{value:!0});var l,c=n("7+uW"),u=n("+Uzz"),d={name:"sidebar",mounted:function(){u.TweenMax.set(this.$el,{x:this.$el.offsetWidth})},computed:{open:function(){return this.$store.state.ui.sidebarOpen},component:function(){return this.$store.state.ui.sidebarComponent}},watch:{open:function(e){var t=e?0:this.$el.offsetWidth;u.TweenMax.to(this.$el,.6,{x:t,ease:u.Power4.easeOut})}}},p=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{class:e.$style.sidebar},[n(e.component,{tag:"component"})],1)},h=[],m={render:p,staticRenderFns:h},f=m,v=n("VU/8"),_=s,b=v(d,f,!1,_,null,null),g=b.exports,w={name:"sidebar-toggle",props:["sidebarComponent","icon"],computed:{open:function(){return this.$store.state.ui.sidebarOpen&&this.$store.state.ui.sidebarComponent===this.sidebarComponent}},methods:{handleClick:function(){this.$store.dispatch("toggleSidebar",{component:this.sidebarComponent})}}},$=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("button",{class:[e.open?e.$style.active:"",e.$style.button],on:{click:e.handleClick}},[n(e.icon,{tag:"component"})],1)},x=[],E={render:$,staticRenderFns:x},y=E,O=n("VU/8"),C=r,S=O(w,y,!1,C,null,null),F=S.exports,M={name:"add-form"},T=function(){var e=this,t=e.$createElement;return(e._self._c||t)("h3",{class:e.$style.title},[e._v("Add Form")])},z=[],B={render:T,staticRenderFns:z},R=B,G=n("VU/8"),A=o,H=G(M,R,!1,A,null,null),I=H.exports,U={name:"search-form"},V=function(){var e=this,t=e.$createElement;return(e._self._c||t)("h3",{class:e.$style.title},[e._v("Search Form")])},N=[],j={render:V,staticRenderFns:N},L=j,k=n("VU/8"),D=i,J=k(U,L,!1,D,null,null),W=J.exports,q={name:"search-icon"},P=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("svg",{attrs:{fill:"#000000",height:"24",viewBox:"0 0 24 24",width:"24",xmlns:"http://www.w3.org/2000/svg"}},[n("path",{attrs:{d:"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"}}),e._v(" "),n("path",{attrs:{d:"M0 0h24v24H0z",fill:"none"}})])},Q=[],K={render:P,staticRenderFns:Q},Y=K,Z=n("VU/8"),X=Z(q,Y,!1,null,null,null),ee=X.exports,te={name:"search-icon"},ne=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("svg",{attrs:{fill:"#000000",height:"24",viewBox:"0 0 24 24",width:"24",xmlns:"http://www.w3.org/2000/svg"}},[n("path",{attrs:{d:"M0 0h24v24H0z",fill:"none"}}),e._v(" "),n("path",{attrs:{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"}})])},se=[],re={render:ne,staticRenderFns:se},oe=re,ie=n("VU/8"),ae=ie(te,oe,!1,null,null,null),le=ae.exports,ce={name:"app",components:{Sidebar:g,SidebarToggle:F},data:function(){return{addForm:I,searchForm:W,searchIcon:ee,addIcon:le}}},ue=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{attrs:{id:"app"}},[n("div",{class:e.$style.container}),e._v(" "),n("sidebar"),e._v(" "),n("div",{class:e.$style.toggles},[n("sidebar-toggle",{attrs:{sidebarComponent:e.addForm,icon:e.searchIcon}}),e._v(" "),n("sidebar-toggle",{attrs:{sidebarComponent:e.searchForm,icon:e.addIcon}})],1)],1)},de=[],pe={render:ue,staticRenderFns:de},he=pe,me=n("VU/8"),fe=a,ve=me(ce,he,!1,fe,null,null),_e=ve.exports,be=n("NYxO"),ge=n("bOdI"),we=n.n(ge),$e={sidebarOpen:!1,sidebarComponent:null},xe={sidebarOpen:function(e){return e.sidebarOpen},sidebarComponent:function(e){return e.sidebarComponent}},Ee={toggleSidebar:function(e,t){var n=e.commit,s=(e.state,t.component);n("TOGGLE_SIDEBAR"),n("SET_SIDEBAR_COMPONENT",s)}},ye=(l={},we()(l,"TOGGLE_SIDEBAR",function(e){e.sidebarOpen=!e.sidebarOpen}),we()(l,"SET_SIDEBAR_COMPONENT",function(e,t){e.sidebarComponent=t}),l),Oe={state:$e,getters:xe,actions:Ee,mutations:ye};c.a.use(be.a);var Ce=new be.a.Store({modules:{ui:Oe},strict:!1});c.a.config.productionTip=!1,new c.a({el:"#app",store:Ce,template:"",components:{App:_e}})},wpMw:function(e,t){e.exports={sidebar:"_1Akv3QSGkfLjHLmQBua5gq_0"}},z8r5:function(e,t){}},["NHnr"]); 2 | //# sourceMappingURL=app.cc4efbd447cb00403ba7.js.map -------------------------------------------------------------------------------- /docs/sidebar-dynamic/static/js/manifest.ecfa1adc4a7519c26d6b.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var i,u,f,s=0,p=[];s 2 | 3 | 4 | 5 | 6 | 7 | sidebar 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/sidebar/static/css/app.e439c225a7a4e3d818fb42e3f740d862.css: -------------------------------------------------------------------------------- 1 | :root{--accent-color:#ffcb08;--primary-color:#820263;--dark-color:#2e294e}*{box-sizing:border-box}._1yQEW-OB4Ybyf_vE6oWyGO_1{position:fixed;left:0;top:0;height:100vh;width:100vw;background-color:var(--primary-color)}._1Akv3QSGkfLjHLmQBua5gq_0{position:fixed;right:0;top:0;width:300px;height:100vh;max-width:90vw;background-color:var(--accent-color)}._2lbLj0f9KsKJTS3AY46M7w_0{position:fixed;bottom:1rem;right:1rem;padding:0;height:50px;width:50px;border:3px solid transparent;border-radius:50%;background-color:transparent;color:var(--dark-color);cursor:pointer;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;line-height:0;transition:transform .3s ease-out,border-color .3s ease-out}._2lbLj0f9KsKJTS3AY46M7w_0 svg{height:100%;width:100%;fill:var(--accent-color);transition:fill .3s ease-out}._2lbLj0f9KsKJTS3AY46M7w_0:focus{outline:none;border-color:var(--accent-color)}.n02dqwlexV56EeqjpzyEx_0{transform:rotate(45deg)}.n02dqwlexV56EeqjpzyEx_0 svg{fill:var(--primary-color)}.n02dqwlexV56EeqjpzyEx_0:focus{border-color:var(--primary-color)} 2 | /*# sourceMappingURL=app.e439c225a7a4e3d818fb42e3f740d862.css.map */ -------------------------------------------------------------------------------- /docs/sidebar/static/css/app.e439c225a7a4e3d818fb42e3f740d862.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["app.e439c225a7a4e3d818fb42e3f740d862.css"],"names":[],"mappings":"AACA,MACE,uBAAwB,AACxB,wBAAyB,AACzB,oBAAsB,CACvB,AACD,EAEU,qBAAuB,CAChC,AAGD,2BACE,eAAgB,AAChB,OAAQ,AACR,MAAO,AACP,aAAc,AACd,YAAa,AACb,qCAAuC,CACxC,AAED,2BACE,eAAgB,AAChB,QAAS,AACT,MAAO,AACP,YAAa,AACb,aAAc,AACd,eAAgB,AAChB,oCAAsC,CACvC,AAED,2BACE,eAAgB,AAChB,YAAa,AACb,WAAY,AACZ,UAAW,AACX,YAAa,AACb,WAAY,AACZ,6BAA8B,AAC9B,kBAAmB,AACnB,6BAA8B,AAC9B,wBAAyB,AACzB,eAAgB,AAEhB,oBAAqB,AACrB,aAAc,AAEV,sBAAuB,AACnB,mBAAoB,AAExB,qBAAsB,AAClB,uBAAwB,AAChC,cAAe,AAGf,2DAAkE,CAEnE,AACD,+BACE,YAAa,AACb,WAAY,AACZ,yBAA0B,AAE1B,4BAAgC,CACjC,AACD,iCACE,aAAc,AACd,gCAAkC,CACnC,AACD,yBAEU,uBAAyB,CAClC,AACD,6BACE,yBAA2B,CAC5B,AACD,+BACE,iCAAmC,CACpC","file":"app.e439c225a7a4e3d818fb42e3f740d862.css","sourcesContent":["\n:root{\n --accent-color: #FFCB08;\n --primary-color: #820263;\n --dark-color: #2E294E;\n}\n*{\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n\n._1yQEW-OB4Ybyf_vE6oWyGO_1{\n position: fixed;\n left: 0;\n top: 0;\n height: 100vh;\n width: 100vw;\n background-color: var(--primary-color);\n}\n\n._1Akv3QSGkfLjHLmQBua5gq_0{\n position: fixed;\n right: 0;\n top: 0;\n width: 300px;\n height: 100vh;\n max-width: 90vw;\n background-color: var(--accent-color);\n}\n\n._2lbLj0f9KsKJTS3AY46M7w_0{\n position: fixed;\n bottom: 1rem;\n right: 1rem;\n padding: 0;\n height: 50px;\n width: 50px;\n border: 3px solid transparent;\n border-radius: 50%;\n background-color: transparent;\n color: var(--dark-color);\n cursor: pointer;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n line-height: 0;\n -webkit-transition: border-color 300ms ease-out, -webkit-transform 300ms ease-out;\n transition: border-color 300ms ease-out, -webkit-transform 300ms ease-out;\n transition: transform 300ms ease-out, border-color 300ms ease-out;\n transition: transform 300ms ease-out, border-color 300ms ease-out, -webkit-transform 300ms ease-out;\n}\n._2lbLj0f9KsKJTS3AY46M7w_0 svg{\n height: 100%;\n width: 100%;\n fill: var(--accent-color);\n -webkit-transition: fill 300ms ease-out;\n transition: fill 300ms ease-out;\n}\n._2lbLj0f9KsKJTS3AY46M7w_0:focus{\n outline: none;\n border-color: var(--accent-color);\n}\n.n02dqwlexV56EeqjpzyEx_0{\n -webkit-transform: rotate(45deg);\n transform: rotate(45deg);\n}\n.n02dqwlexV56EeqjpzyEx_0 svg{\n fill: var(--primary-color);\n}\n.n02dqwlexV56EeqjpzyEx_0:focus{\n border-color: var(--primary-color);\n}\n\n"]} -------------------------------------------------------------------------------- /docs/sidebar/static/js/app.7e8ea3700ad2708b65ba.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],{DWur:function(e,t){e.exports={container:"_1yQEW-OB4Ybyf_vE6oWyGO_1"}},LltD:function(e,t){e.exports={sidebar:"_1Akv3QSGkfLjHLmQBua5gq_0"}},NHnr:function(e,t,n){"use strict";function s(e){this.$style=n("LltD")}function i(e){this.$style=n("mf0t")}function r(e){n("bFqF"),this.$style=n("DWur")}Object.defineProperty(t,"__esModule",{value:!0});var a=n("7+uW"),o=n("+Uzz"),l={name:"sidebar",mounted:function(){o.TweenMax.set(this.$el,{x:this.$el.offsetWidth})},computed:{open:function(){return this.$store.state.ui.sidebarOpen}},watch:{open:function(e){var t=e?0:this.$el.offsetWidth;o.TweenMax.to(this.$el,.6,{x:t,ease:o.Power4.easeOut})}}},c=function(){var e=this,t=e.$createElement;return(e._self._c||t)("div",{class:e.$style.sidebar})},u=[],d={render:c,staticRenderFns:u},p=d,f=n("VU/8"),h=s,b=f(l,p,!1,h,null,null),v=b.exports,m={name:"sidebar-toggle",computed:{open:function(){return this.$store.state.ui.sidebarOpen}},methods:{handleClick:function(){this.$store.dispatch("toggleSidebar")}}},_=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("button",{class:[e.open?e.$style.active:"",e.$style.button],on:{click:e.handleClick}},[n("svg",{attrs:{fill:"#000000",height:"24",viewBox:"0 0 24 24",width:"24",xmlns:"http://www.w3.org/2000/svg"}},[n("path",{attrs:{d:"M0 0h24v24H0z",fill:"none"}}),e._v(" "),n("path",{attrs:{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"}})])])},g=[],$={render:_,staticRenderFns:g},w=$,x=n("VU/8"),O=i,y=x(m,w,!1,O,null,null),E=y.exports,S={name:"app",components:{Sidebar:v,SidebarToggle:E}},F=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{attrs:{id:"app"}},[n("div",{class:e.$style.container}),e._v(" "),n("sidebar"),e._v(" "),n("sidebar-toggle")],1)},L=[],T={render:F,staticRenderFns:L},W=T,k=n("VU/8"),z=r,A=k(S,W,!1,z,null,null),D=A.exports,G=n("NYxO"),M=n("bOdI"),q=n.n(M),B={sidebarOpen:!1},H={sidebarOpen:function(e){return e.sidebarOpen}},R={toggleSidebar:function(e){var t=e.commit;e.state;t("TOGGLE_SIDEBAR")}},V=q()({},"TOGGLE_SIDEBAR",function(e){e.sidebarOpen=!e.sidebarOpen}),j={state:B,getters:H,actions:R,mutations:V};a.a.use(G.a);var U=new G.a.Store({modules:{ui:j},strict:!1});a.a.config.productionTip=!1,new a.a({el:"#app",store:U,template:"",components:{App:D}})},bFqF:function(e,t){},mf0t:function(e,t){e.exports={button:"_2lbLj0f9KsKJTS3AY46M7w_0",active:"n02dqwlexV56EeqjpzyEx_0"}}},["NHnr"]); 2 | //# sourceMappingURL=app.7e8ea3700ad2708b65ba.js.map -------------------------------------------------------------------------------- /docs/sidebar/static/js/manifest.0dc805fcf281e9020471.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,a,c){for(var i,u,f,s=0,p=[];sBoilerplate for an Advanced GraphQL Server 2 | 3 |
4 | 5 | ![](https://imgur.com/lIi4YrZ.png) 6 | 7 |
🚀 Bootstrap your GraphQL server within seconds
8 |
Advanced starter kit for a flexible GraphQL server for Node.js - based on best practices from the GraphQL community.
9 | 10 | ## Features 11 | 12 | - **Scalable GraphQL server:** The server uses [`graphql-yoga`](https://github.com/prisma/graphql-yoga) which is based on Apollo Server & Express 13 | - **GraphQL database:** Includes GraphQL database binding to [Prisma](https://www.prismagraphql.com) (running on MySQL) 14 | - **Authentication**: Signup and login workflows are ready to use for your users 15 | - **Tooling**: Out-of-the-box support for [GraphQL Playground](https://github.com/prisma/graphql-playground) & [query performance tracing](https://github.com/apollographql/apollo-tracing) 16 | - **Extensible**: Simple and flexible [data model](./database/datamodel.graphql) – easy to adjust and extend 17 | - **No configuration overhead**: Preconfigured [`graphql-config`](https://github.com/prisma/graphql-config) setup 18 | 19 | ## Requirements 20 | 21 | You need to have the [GraphQL CLI](https://github.com/graphql-cli/graphql-cli) installed to bootstrap your GraphQL server using `graphql create`: 22 | 23 | ```sh 24 | npm install -g graphql-cli 25 | ``` 26 | 27 | ## Getting started 28 | 29 | ```sh 30 | # 1. Bootstrap GraphQL server in directory `my-app`, based on `node-advanced` boilerplate 31 | graphql create my-app --boilerplate node-advanced 32 | 33 | # 2. When prompted, deploy the Prisma service to a _public cluster_ 34 | 35 | # 3. Navigate to the new project 36 | cd my-app 37 | 38 | # 4. Start server (runs on http://localhost:4000) and open GraphQL Playground 39 | yarn dev 40 | ``` 41 | 42 | ![](https://imgur.com/hElq68i.png) 43 | 44 | ## Documentation 45 | 46 | ### Commands 47 | 48 | * `yarn start` starts GraphQL server on `http://localhost:4000` 49 | * `yarn dev` starts GraphQL server on `http://localhost:4000` _and_ opens GraphQL Playground 50 | * `yarn playground` opens the GraphQL Playground for the `projects` from [`.graphqlconfig.yml`](./.graphqlconfig.yml) 51 | * `yarn prisma ` gives access to local version of Prisma CLI (e.g. `yarn prisma deploy`) 52 | 53 | > **Note**: We recommend that you're using `yarn dev` during development as it will give you access to the GraphQL API or your server (defined by the [application schema](./src/schema.graphql)) as well as to the Prisma API directly (defined by the [Prisma database schema](./generated/prisma.graphql)). If you're starting the server with `yarn start`, you'll only be able to access the API of the application schema. 54 | 55 | ### Project structure 56 | 57 | ![](https://imgur.com/95faUsa.png) 58 | 59 | | File name               | Description         

| 60 | | :-- | :-- | 61 | | `├── .env` | Defines environment variables | 62 | | `├── .graphqlconfig.yml` | Configuration file based on [`graphql-config`](https://github.com/prisma/graphql-config) (e.g. used by GraphQL Playground).| 63 | | `└── database ` (_directory_) | _Contains all files that are related to the Prisma database service_ |\ 64 | | `  ├── prisma.yml` | The root configuration file for your Prisma database service ([docs](https://www.prismagraphql.com/docs/reference/prisma.yml/overview-and-example-foatho8aip)) | 65 | | `  └── datamodel.graphql` | Defines your data model (written in [GraphQL SDL](https://blog.graph.cool/graphql-sdl-schema-definition-language-6755bcb9ce51)) | 66 | | `└── src ` (_directory_) | _Contains the source files for your GraphQL server_ | 67 | | `  ├── index.js` | The entry point for your GraphQL server | 68 | | `  ├── schema.graphql` | The **application schema** defining the API exposed to client applications | 69 | | `  ├── resolvers` (_directory_) | _Contains the implementation of the resolvers for the application schema_ | 70 | | `  └── generated` (_directory_) | _Contains generated files_ | 71 | | `    └── prisma.grapghql` | The **Prisma database schema** defining the Prisma GraphQL API | 72 | 73 | ## Contributing 74 | 75 | The GraphQL boilerplates are maintained by the GraphQL community, with official support from the [Apollo](https://dev-blog.apollodata.com) & [Graphcool](https://blog.graph.cool/) teams. 76 | 77 | Your feedback is **very helpful**, please share your opinion and thoughts! If you have any questions or want to contribute yourself, join the [`#graphql-boilerplate`](https://graphcool.slack.com/messages/graphql-boilerplate) channel on our [Slack](https://graphcool.slack.com/). -------------------------------------------------------------------------------- /prisma-auth0/server/database/datamodel.graphql: -------------------------------------------------------------------------------- 1 | type Post { 2 | id: ID! @unique 3 | createdAt: DateTime! 4 | updatedAt: DateTime! 5 | isPublished: Boolean! @default(value: "false") 6 | title: String! 7 | text: String! 8 | author: User! 9 | } 10 | 11 | type User { 12 | id: ID! @unique 13 | email: String! @unique 14 | password: String! 15 | name: String! 16 | posts: [Post!]! 17 | } 18 | -------------------------------------------------------------------------------- /prisma-auth0/server/database/prisma.yml: -------------------------------------------------------------------------------- 1 | # the name for the service (will be part of the service's HTTP endpoint) 2 | service: server 3 | 4 | # the cluster and stage the service is deployed to 5 | stage: ${env:PRISMA_STAGE} 6 | 7 | # to disable authentication: 8 | # disableAuth: true 9 | secret: ${env:PRISMA_SECRET} 10 | 11 | # the file path pointing to your data model 12 | datamodel: datamodel.graphql 13 | 14 | # seed your service with initial data based on seed.graphql 15 | seed: 16 | import: seed.graphql 17 | 18 | cluster: ${env:PRISMA_CLUSTER} -------------------------------------------------------------------------------- /prisma-auth0/server/database/seed.graphql: -------------------------------------------------------------------------------- 1 | mutation { 2 | createUser(data: { 3 | email: "developer@example.com" 4 | password: "$2a$10$hACwQ5/HQI6FhbIISOUVeusy3sKyUDhSq36fF5d/54aAdiygJPFzm" # plaintext password: "nooneknows" 5 | name: "Sarah" 6 | posts: { 7 | create: [{ 8 | title: "Hello World" 9 | text: "This is my first blog post ever!" 10 | isPublished: true 11 | }, { 12 | title: "My Second Post" 13 | text: "My first post was good, but this one is better!" 14 | isPublished: true 15 | }, { 16 | title: "Solving World Hunger" 17 | text: "This is a draft..." 18 | isPublished: false 19 | }] 20 | } 21 | }) { 22 | id 23 | } 24 | } -------------------------------------------------------------------------------- /prisma-auth0/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "scripts": { 4 | "start": "nodemon -e js,graphql -x node -r dotenv/config src/index.js", 5 | "debug": "nodemon -e js,graphql -x node --inspect -r dotenv/config src/index.js", 6 | "playground": "graphql playground", 7 | "dev": "npm-run-all --parallel start playground" 8 | }, 9 | "dependencies": { 10 | "bcryptjs": "2.4.3", 11 | "graphql-yoga": "1.2.1", 12 | "jsonwebtoken": "8.1.1", 13 | "prisma-binding": "1.4.0" 14 | }, 15 | "devDependencies": { 16 | "dotenv": "4.0.0", 17 | "graphql-cli": "2.13.0", 18 | "nodemon": "1.14.11", 19 | "npm-run-all": "4.1.2", 20 | "prisma": "1.1.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /prisma-auth0/server/src/index.js: -------------------------------------------------------------------------------- 1 | const { GraphQLServer } = require('graphql-yoga') 2 | const { Prisma } = require('prisma-binding') 3 | const resolvers = require('./resolvers') 4 | 5 | const server = new GraphQLServer({ 6 | typeDefs: 'src/schema.graphql', 7 | resolvers, 8 | context: req => ({ 9 | ...req, 10 | db: new Prisma({ 11 | typeDefs: 'src/generated/prisma.graphql', 12 | endpoint: process.env.PRISMA_ENDPOINT, // the endpoint of the Prisma DB service (value is set in .env) 13 | secret: process.env.PRISMA_SECRET, // taken from database/prisma.yml (value is set in .env) 14 | debug: true, // log all GraphQL queries & mutations 15 | }), 16 | }), 17 | }) 18 | 19 | server.start(() => console.log('Server is running on http://localhost:4000')) 20 | -------------------------------------------------------------------------------- /prisma-auth0/server/src/resolvers/AuthPayload.js: -------------------------------------------------------------------------------- 1 | const { Context } = require('../utils') 2 | 3 | const AuthPayload = { 4 | user: async ({ user: { id } }, args, ctx, info) => { 5 | return ctx.db.query.user({ where: { id } }, info) 6 | }, 7 | } 8 | 9 | module.exports = { AuthPayload } -------------------------------------------------------------------------------- /prisma-auth0/server/src/resolvers/Mutation/auth.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require('bcryptjs') 2 | const jwt = require('jsonwebtoken') 3 | const { Context } = require( '../../utils') 4 | 5 | const auth = { 6 | async signup(parent, args, ctx, info) { 7 | const password = await bcrypt.hash(args.password, 10) 8 | const user = await ctx.db.mutation.createUser({ 9 | data: { ...args, password }, 10 | }) 11 | 12 | return { 13 | token: jwt.sign({ userId: user.id }, process.env.APP_SECRET), 14 | user, 15 | } 16 | }, 17 | 18 | async login(parent, { email, password }, ctx, info) { 19 | const user = await ctx.db.query.user({ where: { email } }) 20 | if (!user) { 21 | throw new Error(`No such user found for email: ${email}`) 22 | } 23 | 24 | const valid = await bcrypt.compare(password, user.password) 25 | if (!valid) { 26 | throw new Error('Invalid password') 27 | } 28 | 29 | return { 30 | token: jwt.sign({ userId: user.id }, process.env.APP_SECRET), 31 | user, 32 | } 33 | }, 34 | } 35 | 36 | module.exports = { auth } 37 | -------------------------------------------------------------------------------- /prisma-auth0/server/src/resolvers/Mutation/post.js: -------------------------------------------------------------------------------- 1 | const { getUserId, Context } = require('../../utils') 2 | 3 | const post = { 4 | async createDraft(parent, { title, text }, ctx, info) { 5 | const userId = getUserId(ctx) 6 | return ctx.db.mutation.createPost( 7 | { 8 | data: { 9 | title, 10 | text, 11 | isPublished: false, 12 | author: { 13 | connect: { id: userId }, 14 | }, 15 | }, 16 | }, 17 | info 18 | ) 19 | }, 20 | 21 | async publish(parent, { id }, ctx, info) { 22 | const userId = getUserId(ctx) 23 | const postExists = await ctx.db.exists.Post({ 24 | id, 25 | author: { id: userId }, 26 | }) 27 | if (!postExists) { 28 | throw new Error(`Post not found or you're not the author`) 29 | } 30 | 31 | return ctx.db.mutation.updatePost( 32 | { 33 | where: { id }, 34 | data: { isPublished: true }, 35 | }, 36 | info, 37 | ) 38 | }, 39 | 40 | async deletePost(parent, { id }, ctx, info) { 41 | const userId = getUserId(ctx) 42 | const postExists = await ctx.db.exists.Post({ 43 | id, 44 | author: { id: userId }, 45 | }) 46 | if (!postExists) { 47 | throw new Error(`Post not found or you're not the author`) 48 | } 49 | 50 | return ctx.db.mutation.deletePost({ where: { id } }) 51 | }, 52 | } 53 | 54 | module.exports = { post } 55 | -------------------------------------------------------------------------------- /prisma-auth0/server/src/resolvers/Query.js: -------------------------------------------------------------------------------- 1 | const { getUserId, Context } = require('../utils') 2 | 3 | const Query = { 4 | feed(parent, args, ctx, info) { 5 | return ctx.db.query.posts({ where: { isPublished: true } }, info) 6 | }, 7 | 8 | drafts(parent, args, ctx, info) { 9 | const id = getUserId(ctx) 10 | 11 | const where = { 12 | isPublished: false, 13 | author: { 14 | id 15 | } 16 | } 17 | 18 | return ctx.db.query.posts({ where }, info) 19 | }, 20 | 21 | post(parent, { id }, ctx, info) { 22 | return ctx.db.query.post({ where: { id } }, info) 23 | }, 24 | 25 | me(parent, args, ctx, info) { 26 | const id = getUserId(ctx) 27 | return ctx.db.query.user({ where: { id } }, info) 28 | }, 29 | } 30 | 31 | module.exports = { Query } 32 | -------------------------------------------------------------------------------- /prisma-auth0/server/src/resolvers/index.js: -------------------------------------------------------------------------------- 1 | const { Query } = require('./Query') 2 | const { auth } = require('./Mutation/auth') 3 | const { post } = require('./Mutation/post') 4 | const { AuthPayload } = require('./AuthPayload') 5 | 6 | module.exports = { 7 | Query, 8 | Mutation: { 9 | ...auth, 10 | ...post, 11 | }, 12 | AuthPayload, 13 | } 14 | -------------------------------------------------------------------------------- /prisma-auth0/server/src/schema.graphql: -------------------------------------------------------------------------------- 1 | # import Post from "./generated/prisma.graphql" 2 | 3 | type Query { 4 | feed: [Post!]! 5 | drafts: [Post!]! 6 | post(id: ID!): Post! 7 | me: User 8 | } 9 | 10 | type Mutation { 11 | signup(email: String!, password: String!, name: String!): AuthPayload! 12 | login(email: String!, password: String!): AuthPayload! 13 | createDraft(title: String!, text: String!): Post! 14 | publish(id: ID!): Post! 15 | deletePost(id: ID!): Post! 16 | } 17 | 18 | type AuthPayload { 19 | token: String! 20 | user: User! 21 | } 22 | 23 | type User { 24 | id: ID! 25 | email: String! 26 | name: String! 27 | posts: [Post!]! 28 | } 29 | -------------------------------------------------------------------------------- /prisma-auth0/server/src/utils.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken') 2 | 3 | function getUserId(ctx) { 4 | const Authorization = ctx.request.get('Authorization') 5 | if (Authorization) { 6 | const token = Authorization.replace('Bearer ', '') 7 | const { userId } = jwt.verify(token, process.env.APP_SECRET) 8 | return userId 9 | } 10 | 11 | throw new AuthError() 12 | } 13 | 14 | class AuthError extends Error { 15 | constructor() { 16 | super('Not authorized') 17 | } 18 | } 19 | 20 | module.exports = { 21 | getUserId, 22 | AuthError 23 | } -------------------------------------------------------------------------------- /sidebar-dynamic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"], 9 | "env": { 10 | "test": { 11 | "presets": ["env", "stage-2"] } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sidebar-dynamic/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /sidebar-dynamic/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | -------------------------------------------------------------------------------- /sidebar-dynamic/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | 'rules': { 20 | // allow paren-less arrow functions 21 | 'arrow-parens': 0, 22 | // allow async-await 23 | 'generator-star-spacing': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sidebar-dynamic/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /sidebar-dynamic/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sidebar-dynamic/README.md: -------------------------------------------------------------------------------- 1 | # Dynamic Content Sidebar 2 | 3 | [Read the Medium tutorial first!](https://medium.com/@rmmmsy/creating-a-sidebar-with-dynamic-content-using-vue-and-vuex-88e904894e00) 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /sidebar-dynamic/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /sidebar-dynamic/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sidebar-dynamic/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/sidebar-dynamic/build/logo.png -------------------------------------------------------------------------------- /sidebar-dynamic/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const pkg = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | return path.posix.join(assetsSubDirectory, _path) 12 | } 13 | 14 | exports.cssLoaders = function (options) { 15 | options = options || {} 16 | 17 | const cssLoader = { 18 | loader: 'css-loader', 19 | options: { 20 | sourceMap: options.sourceMap 21 | } 22 | } 23 | 24 | var postcssLoader = { 25 | loader: 'postcss-loader', 26 | options: { 27 | sourceMap: options.sourceMap 28 | } 29 | } 30 | 31 | // generate loader string to be used with extract text plugin 32 | function generateLoaders (loader, loaderOptions) { 33 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 34 | if (loader) { 35 | loaders.push({ 36 | loader: loader + '-loader', 37 | options: Object.assign({}, loaderOptions, { 38 | sourceMap: options.sourceMap 39 | }) 40 | }) 41 | } 42 | 43 | // Extract CSS when that option is specified 44 | // (which is the case during production build) 45 | if (options.extract) { 46 | return ExtractTextPlugin.extract({ 47 | use: loaders, 48 | fallback: 'vue-style-loader' 49 | }) 50 | } else { 51 | return ['vue-style-loader'].concat(loaders) 52 | } 53 | } 54 | 55 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 56 | return { 57 | css: generateLoaders(), 58 | postcss: generateLoaders(), 59 | less: generateLoaders('less'), 60 | sass: generateLoaders('sass', { indentedSyntax: true }), 61 | scss: generateLoaders('sass'), 62 | stylus: generateLoaders('stylus'), 63 | styl: generateLoaders('stylus') 64 | } 65 | } 66 | 67 | // Generate loaders for standalone style files (outside of .vue) 68 | exports.styleLoaders = function (options) { 69 | const output = [] 70 | const loaders = exports.cssLoaders(options) 71 | for (const extension in loaders) { 72 | const loader = loaders[extension] 73 | output.push({ 74 | test: new RegExp('\\.' + extension + '$'), 75 | use: loader 76 | }) 77 | } 78 | return output 79 | } 80 | 81 | exports.createNotifierCallback = function () { 82 | const notifier = require('node-notifier') 83 | 84 | return (severity, errors) => { 85 | if (severity !== 'error') { 86 | return 87 | } 88 | const error = errors[0] 89 | 90 | const filename = error.file.split('!').pop() 91 | notifier.notify({ 92 | title: pkg.name, 93 | message: severity + ': ' + error.name, 94 | subtitle: filename || '', 95 | icon: path.join(__dirname, 'logo.png') 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /sidebar-dynamic/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | 10 | module.exports = { 11 | loaders: utils.cssLoaders({ 12 | sourceMap: sourceMapEnabled, 13 | extract: isProduction 14 | }), 15 | cssSourceMap: sourceMapEnabled, 16 | transformToRequire: { 17 | video: 'src', 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /sidebar-dynamic/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | module.exports = { 12 | context: path.resolve(__dirname, '../'), 13 | entry: { 14 | app: './src/main.js' 15 | }, 16 | output: { 17 | path: config.build.assetsRoot, 18 | filename: '[name].js', 19 | publicPath: process.env.NODE_ENV === 'production' 20 | ? config.build.assetsPublicPath 21 | : config.dev.assetsPublicPath 22 | }, 23 | resolve: { 24 | extensions: ['.js', '.vue', '.json'], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.esm.js', 27 | '@': resolve('src'), 28 | } 29 | }, 30 | module: { 31 | rules: [ 32 | ...(config.dev.useEslint? [{ 33 | test: /\.(js|vue)$/, 34 | loader: 'eslint-loader', 35 | enforce: 'pre', 36 | include: [resolve('src'), resolve('test')], 37 | options: { 38 | formatter: require('eslint-friendly-formatter'), 39 | emitWarning: !config.dev.showEslintErrorsInOverlay 40 | } 41 | }] : []), 42 | { 43 | test: /\.vue$/, 44 | loader: 'vue-loader', 45 | options: vueLoaderConfig 46 | }, 47 | { 48 | test: /\.js$/, 49 | loader: 'babel-loader', 50 | include: [resolve('src'), resolve('test')] 51 | }, 52 | { 53 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 54 | loader: 'url-loader', 55 | options: { 56 | limit: 10000, 57 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 58 | } 59 | }, 60 | { 61 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 62 | loader: 'url-loader', 63 | options: { 64 | limit: 10000, 65 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 66 | } 67 | }, 68 | { 69 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 70 | loader: 'url-loader', 71 | options: { 72 | limit: 10000, 73 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 74 | } 75 | } 76 | ] 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /sidebar-dynamic/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const portfinder = require('portfinder') 10 | 11 | const devWebpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 14 | }, 15 | // cheap-module-eval-source-map is faster for development 16 | devtool: config.dev.devtool, 17 | 18 | // these devServer options should be customized in /config/index.js 19 | devServer: { 20 | clientLogLevel: 'warning', 21 | historyApiFallback: true, 22 | hot: true, 23 | host: process.env.HOST || config.dev.host, 24 | port: process.env.PORT || config.dev.port, 25 | open: config.dev.autoOpenBrowser, 26 | overlay: config.dev.errorOverlay ? { 27 | warnings: false, 28 | errors: true, 29 | } : false, 30 | publicPath: config.dev.assetsPublicPath, 31 | proxy: config.dev.proxyTable, 32 | quiet: true, // necessary for FriendlyErrorsPlugin 33 | watchOptions: { 34 | poll: config.dev.poll, 35 | } 36 | }, 37 | plugins: [ 38 | new webpack.DefinePlugin({ 39 | 'process.env': require('../config/dev.env') 40 | }), 41 | new webpack.HotModuleReplacementPlugin(), 42 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 43 | new webpack.NoEmitOnErrorsPlugin(), 44 | // https://github.com/ampedandwired/html-webpack-plugin 45 | new HtmlWebpackPlugin({ 46 | filename: 'index.html', 47 | template: 'index.html', 48 | inject: true 49 | }), 50 | ] 51 | }) 52 | 53 | module.exports = new Promise((resolve, reject) => { 54 | portfinder.basePort = process.env.PORT || config.dev.port 55 | portfinder.getPort((err, port) => { 56 | if (err) { 57 | reject(err) 58 | } else { 59 | // publish the new Port, necessary for e2e tests 60 | process.env.PORT = port 61 | // add port to devServer config 62 | devWebpackConfig.devServer.port = port 63 | 64 | // Add FriendlyErrorsPlugin 65 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 66 | compilationSuccessInfo: { 67 | messages: [`Your application is running here: http://${config.dev.host}:${port}`], 68 | }, 69 | onErrors: config.dev.notifyOnErrors 70 | ? utils.createNotifierCallback() 71 | : undefined 72 | })) 73 | 74 | resolve(devWebpackConfig) 75 | } 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /sidebar-dynamic/build/webpack.test.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // This is the webpack config used for unit tests. 3 | 4 | const utils = require('./utils') 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | 9 | const webpackConfig = merge(baseWebpackConfig, { 10 | // use inline sourcemap for karma-sourcemap-loader 11 | module: { 12 | rules: utils.styleLoaders() 13 | }, 14 | devtool: '#inline-source-map', 15 | resolveLoader: { 16 | alias: { 17 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option 18 | // see discussion at https://github.com/vuejs/vue-loader/issues/724 19 | 'scss-loader': 'sass-loader' 20 | } 21 | }, 22 | plugins: [ 23 | new webpack.DefinePlugin({ 24 | 'process.env': require('../config/test.env') 25 | }) 26 | ] 27 | }) 28 | 29 | // no need for app entry during tests 30 | delete webpackConfig.entry 31 | 32 | module.exports = webpackConfig 33 | -------------------------------------------------------------------------------- /sidebar-dynamic/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /sidebar-dynamic/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.3 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.HOST, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | // Template for index.html 53 | index: path.resolve(__dirname, '../dist/index.html'), 54 | 55 | // Paths 56 | assetsRoot: path.resolve(__dirname, '../dist'), 57 | assetsSubDirectory: 'static', 58 | assetsPublicPath: '/', 59 | 60 | /** 61 | * Source Maps 62 | */ 63 | 64 | productionSourceMap: true, 65 | // https://webpack.js.org/configuration/devtool/#production 66 | devtool: '#source-map', 67 | 68 | // Gzip off by default as many popular static hosts such as 69 | // Surge or Netlify already gzip all static assets for you. 70 | // Before setting to `true`, make sure to: 71 | // npm install --save-dev compression-webpack-plugin 72 | productionGzip: false, 73 | productionGzipExtensions: ['js', 'css'], 74 | 75 | // Run the build command with an extra argument to 76 | // View the bundle analyzer report after build finishes: 77 | // `npm run build --report` 78 | // Set to `true` or `false` to always turn it on or off 79 | bundleAnalyzerReport: process.env.npm_config_report 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sidebar-dynamic/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /sidebar-dynamic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | sidebar 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sidebar-dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sidebar", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "ramsaylanier", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "lint": "eslint --ext .js,.vue src", 11 | "build": "node build/build.js" 12 | }, 13 | "dependencies": { 14 | "css-loader": "^0.28.7", 15 | "gsap": "^1.20.3", 16 | "vue": "^2.5.2", 17 | "vue-style-loader": "^3.0.3", 18 | "vuex": "^3.0.1" 19 | }, 20 | "devDependencies": { 21 | "autoprefixer": "^7.1.2", 22 | "babel-core": "^6.22.1", 23 | "babel-eslint": "^7.1.1", 24 | "babel-loader": "^7.1.1", 25 | "babel-plugin-transform-runtime": "^6.22.0", 26 | "babel-preset-env": "^1.3.2", 27 | "babel-preset-stage-2": "^6.22.0", 28 | "babel-register": "^6.22.0", 29 | "chalk": "^2.0.1", 30 | "copy-webpack-plugin": "^4.0.1", 31 | "css-loader": "^0.28.0", 32 | "eslint": "^3.19.0", 33 | "eslint-friendly-formatter": "^3.0.0", 34 | "eslint-loader": "^1.7.1", 35 | "eslint-plugin-html": "^3.0.0", 36 | "eslint-config-standard": "^10.2.1", 37 | "eslint-plugin-promise": "^3.4.0", 38 | "eslint-plugin-standard": "^3.0.1", 39 | "eslint-plugin-import": "^2.7.0", 40 | "eslint-plugin-node": "^5.2.0", 41 | "eventsource-polyfill": "^0.9.6", 42 | "extract-text-webpack-plugin": "^3.0.0", 43 | "file-loader": "^1.1.4", 44 | "friendly-errors-webpack-plugin": "^1.6.1", 45 | "html-webpack-plugin": "^2.30.1", 46 | "webpack-bundle-analyzer": "^2.9.0", 47 | "node-notifier": "^5.1.2", 48 | "postcss-import": "^11.0.0", 49 | "postcss-loader": "^2.0.8", 50 | "semver": "^5.3.0", 51 | "shelljs": "^0.7.6", 52 | "optimize-css-assets-webpack-plugin": "^3.2.0", 53 | "ora": "^1.2.0", 54 | "rimraf": "^2.6.0", 55 | "url-loader": "^0.5.8", 56 | "vue-loader": "^13.3.0", 57 | "vue-style-loader": "^3.0.1", 58 | "vue-template-compiler": "^2.5.2", 59 | "portfinder": "^1.0.13", 60 | "webpack": "^3.6.0", 61 | "webpack-dev-server": "^2.9.1", 62 | "webpack-merge": "^4.1.0" 63 | }, 64 | "engines": { 65 | "node": ">= 4.0.0", 66 | "npm": ">= 3.0.0" 67 | }, 68 | "browserslist": [ 69 | "> 1%", 70 | "last 2 versions", 71 | "not ie <= 8" 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 38 | 39 | 51 | 52 | 69 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/components/addForm.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/components/searchForm.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/components/sidebar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 36 | 37 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/components/sidebarToggle.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | 24 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/icons/add.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/icons/search.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import store from './store/index.js' 6 | 7 | Vue.config.productionTip = false 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#app', 12 | store, 13 | template: '', 14 | components: { App } 15 | }) 16 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import ui from './modules/ui' 4 | 5 | Vue.use(Vuex) 6 | 7 | const debug = process.env.NODE_ENV !== 'production' 8 | 9 | export default new Vuex.Store({ 10 | modules: { 11 | ui 12 | }, 13 | strict: debug 14 | }) 15 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/store/modules/ui.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | 3 | // initial state 4 | // shape: [{ id, quantity }] 5 | const state = { 6 | sidebarOpen: false, 7 | sidebarComponent: null 8 | } 9 | 10 | // getters 11 | const getters = { 12 | sidebarOpen: state => state.sidebarOpen, 13 | sidebarComponent: state => state.sidebarComponent 14 | } 15 | 16 | // actions 17 | const actions = { 18 | toggleSidebar ({ commit, state }, {component}) { 19 | commit(types.TOGGLE_SIDEBAR) 20 | commit(types.SET_SIDEBAR_COMPONENT, component) 21 | } 22 | } 23 | 24 | // mutations 25 | const mutations = { 26 | [types.TOGGLE_SIDEBAR] (state) { 27 | state.sidebarOpen = !state.sidebarOpen 28 | }, 29 | [types.SET_SIDEBAR_COMPONENT] (state, component) { 30 | state.sidebarComponent = component 31 | } 32 | } 33 | 34 | export default { 35 | state, 36 | getters, 37 | actions, 38 | mutations 39 | } 40 | -------------------------------------------------------------------------------- /sidebar-dynamic/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const TOGGLE_SIDEBAR = 'TOGGLE_SIDEBAR' 2 | export const SET_SIDEBAR_COMPONENT = 'SET_SIDEBAR_COMPONENT' 3 | -------------------------------------------------------------------------------- /sidebar-dynamic/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/sidebar-dynamic/static/.gitkeep -------------------------------------------------------------------------------- /sidebar/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"], 9 | "env": { 10 | "test": { 11 | "presets": ["env", "stage-2"] } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sidebar/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /sidebar/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | -------------------------------------------------------------------------------- /sidebar/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | 'rules': { 20 | // allow paren-less arrow functions 21 | 'arrow-parens': 0, 22 | // allow async-await 23 | 'generator-star-spacing': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sidebar/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /sidebar/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sidebar/README.md: -------------------------------------------------------------------------------- 1 | # sidebar 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /sidebar/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /sidebar/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sidebar/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/sidebar/build/logo.png -------------------------------------------------------------------------------- /sidebar/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const pkg = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | return path.posix.join(assetsSubDirectory, _path) 12 | } 13 | 14 | exports.cssLoaders = function (options) { 15 | options = options || {} 16 | 17 | const cssLoader = { 18 | loader: 'css-loader', 19 | options: { 20 | sourceMap: options.sourceMap 21 | } 22 | } 23 | 24 | var postcssLoader = { 25 | loader: 'postcss-loader', 26 | options: { 27 | sourceMap: options.sourceMap 28 | } 29 | } 30 | 31 | // generate loader string to be used with extract text plugin 32 | function generateLoaders (loader, loaderOptions) { 33 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 34 | if (loader) { 35 | loaders.push({ 36 | loader: loader + '-loader', 37 | options: Object.assign({}, loaderOptions, { 38 | sourceMap: options.sourceMap 39 | }) 40 | }) 41 | } 42 | 43 | // Extract CSS when that option is specified 44 | // (which is the case during production build) 45 | if (options.extract) { 46 | return ExtractTextPlugin.extract({ 47 | use: loaders, 48 | fallback: 'vue-style-loader' 49 | }) 50 | } else { 51 | return ['vue-style-loader'].concat(loaders) 52 | } 53 | } 54 | 55 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 56 | return { 57 | css: generateLoaders(), 58 | postcss: generateLoaders(), 59 | less: generateLoaders('less'), 60 | sass: generateLoaders('sass', { indentedSyntax: true }), 61 | scss: generateLoaders('sass'), 62 | stylus: generateLoaders('stylus'), 63 | styl: generateLoaders('stylus') 64 | } 65 | } 66 | 67 | // Generate loaders for standalone style files (outside of .vue) 68 | exports.styleLoaders = function (options) { 69 | const output = [] 70 | const loaders = exports.cssLoaders(options) 71 | for (const extension in loaders) { 72 | const loader = loaders[extension] 73 | output.push({ 74 | test: new RegExp('\\.' + extension + '$'), 75 | use: loader 76 | }) 77 | } 78 | return output 79 | } 80 | 81 | exports.createNotifierCallback = function () { 82 | const notifier = require('node-notifier') 83 | 84 | return (severity, errors) => { 85 | if (severity !== 'error') { 86 | return 87 | } 88 | const error = errors[0] 89 | 90 | const filename = error.file.split('!').pop() 91 | notifier.notify({ 92 | title: pkg.name, 93 | message: severity + ': ' + error.name, 94 | subtitle: filename || '', 95 | icon: path.join(__dirname, 'logo.png') 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /sidebar/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | 10 | module.exports = { 11 | loaders: utils.cssLoaders({ 12 | sourceMap: sourceMapEnabled, 13 | extract: isProduction 14 | }), 15 | cssSourceMap: sourceMapEnabled, 16 | transformToRequire: { 17 | video: 'src', 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /sidebar/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | module.exports = { 12 | context: path.resolve(__dirname, '../'), 13 | entry: { 14 | app: './src/main.js' 15 | }, 16 | output: { 17 | path: config.build.assetsRoot, 18 | filename: '[name].js', 19 | publicPath: process.env.NODE_ENV === 'production' 20 | ? config.build.assetsPublicPath 21 | : config.dev.assetsPublicPath 22 | }, 23 | resolve: { 24 | extensions: ['.js', '.vue', '.json'], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.esm.js', 27 | '@': resolve('src'), 28 | } 29 | }, 30 | module: { 31 | rules: [ 32 | ...(config.dev.useEslint? [{ 33 | test: /\.(js|vue)$/, 34 | loader: 'eslint-loader', 35 | enforce: 'pre', 36 | include: [resolve('src'), resolve('test')], 37 | options: { 38 | formatter: require('eslint-friendly-formatter'), 39 | emitWarning: !config.dev.showEslintErrorsInOverlay 40 | } 41 | }] : []), 42 | { 43 | test: /\.vue$/, 44 | loader: 'vue-loader', 45 | options: vueLoaderConfig 46 | }, 47 | { 48 | test: /\.js$/, 49 | loader: 'babel-loader', 50 | include: [resolve('src'), resolve('test')] 51 | }, 52 | { 53 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 54 | loader: 'url-loader', 55 | options: { 56 | limit: 10000, 57 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 58 | } 59 | }, 60 | { 61 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 62 | loader: 'url-loader', 63 | options: { 64 | limit: 10000, 65 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 66 | } 67 | }, 68 | { 69 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 70 | loader: 'url-loader', 71 | options: { 72 | limit: 10000, 73 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 74 | } 75 | } 76 | ] 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /sidebar/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const portfinder = require('portfinder') 10 | 11 | const devWebpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 14 | }, 15 | // cheap-module-eval-source-map is faster for development 16 | devtool: config.dev.devtool, 17 | 18 | // these devServer options should be customized in /config/index.js 19 | devServer: { 20 | clientLogLevel: 'warning', 21 | historyApiFallback: true, 22 | hot: true, 23 | host: process.env.HOST || config.dev.host, 24 | port: process.env.PORT || config.dev.port, 25 | open: config.dev.autoOpenBrowser, 26 | overlay: config.dev.errorOverlay ? { 27 | warnings: false, 28 | errors: true, 29 | } : false, 30 | publicPath: config.dev.assetsPublicPath, 31 | proxy: config.dev.proxyTable, 32 | quiet: true, // necessary for FriendlyErrorsPlugin 33 | watchOptions: { 34 | poll: config.dev.poll, 35 | } 36 | }, 37 | plugins: [ 38 | new webpack.DefinePlugin({ 39 | 'process.env': require('../config/dev.env') 40 | }), 41 | new webpack.HotModuleReplacementPlugin(), 42 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 43 | new webpack.NoEmitOnErrorsPlugin(), 44 | // https://github.com/ampedandwired/html-webpack-plugin 45 | new HtmlWebpackPlugin({ 46 | filename: 'index.html', 47 | template: 'index.html', 48 | inject: true 49 | }), 50 | ] 51 | }) 52 | 53 | module.exports = new Promise((resolve, reject) => { 54 | portfinder.basePort = process.env.PORT || config.dev.port 55 | portfinder.getPort((err, port) => { 56 | if (err) { 57 | reject(err) 58 | } else { 59 | // publish the new Port, necessary for e2e tests 60 | process.env.PORT = port 61 | // add port to devServer config 62 | devWebpackConfig.devServer.port = port 63 | 64 | // Add FriendlyErrorsPlugin 65 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 66 | compilationSuccessInfo: { 67 | messages: [`Your application is running here: http://${config.dev.host}:${port}`], 68 | }, 69 | onErrors: config.dev.notifyOnErrors 70 | ? utils.createNotifierCallback() 71 | : undefined 72 | })) 73 | 74 | resolve(devWebpackConfig) 75 | } 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /sidebar/build/webpack.test.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // This is the webpack config used for unit tests. 3 | 4 | const utils = require('./utils') 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | 9 | const webpackConfig = merge(baseWebpackConfig, { 10 | // use inline sourcemap for karma-sourcemap-loader 11 | module: { 12 | rules: utils.styleLoaders() 13 | }, 14 | devtool: '#inline-source-map', 15 | resolveLoader: { 16 | alias: { 17 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option 18 | // see discussion at https://github.com/vuejs/vue-loader/issues/724 19 | 'scss-loader': 'sass-loader' 20 | } 21 | }, 22 | plugins: [ 23 | new webpack.DefinePlugin({ 24 | 'process.env': require('../config/test.env') 25 | }) 26 | ] 27 | }) 28 | 29 | // no need for app entry during tests 30 | delete webpackConfig.entry 31 | 32 | module.exports = webpackConfig 33 | -------------------------------------------------------------------------------- /sidebar/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /sidebar/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.3 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.HOST, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | // Template for index.html 53 | index: path.resolve(__dirname, '../dist/index.html'), 54 | 55 | // Paths 56 | assetsRoot: path.resolve(__dirname, '../dist'), 57 | assetsSubDirectory: 'static', 58 | assetsPublicPath: '/', 59 | 60 | /** 61 | * Source Maps 62 | */ 63 | 64 | productionSourceMap: true, 65 | // https://webpack.js.org/configuration/devtool/#production 66 | devtool: '#source-map', 67 | 68 | // Gzip off by default as many popular static hosts such as 69 | // Surge or Netlify already gzip all static assets for you. 70 | // Before setting to `true`, make sure to: 71 | // npm install --save-dev compression-webpack-plugin 72 | productionGzip: false, 73 | productionGzipExtensions: ['js', 'css'], 74 | 75 | // Run the build command with an extra argument to 76 | // View the bundle analyzer report after build finishes: 77 | // `npm run build --report` 78 | // Set to `true` or `false` to always turn it on or off 79 | bundleAnalyzerReport: process.env.npm_config_report 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sidebar/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /sidebar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | sidebar 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sidebar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sidebar", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "ramsaylanier", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "lint": "eslint --ext .js,.vue src", 11 | "build": "node build/build.js" 12 | }, 13 | "dependencies": { 14 | "css-loader": "^0.28.7", 15 | "gsap": "^1.20.3", 16 | "vue": "^2.5.2", 17 | "vue-style-loader": "^3.0.3", 18 | "vuex": "^3.0.1" 19 | }, 20 | "devDependencies": { 21 | "autoprefixer": "^7.1.2", 22 | "babel-core": "^6.22.1", 23 | "babel-eslint": "^7.1.1", 24 | "babel-loader": "^7.1.1", 25 | "babel-plugin-transform-runtime": "^6.22.0", 26 | "babel-preset-env": "^1.3.2", 27 | "babel-preset-stage-2": "^6.22.0", 28 | "babel-register": "^6.22.0", 29 | "chalk": "^2.0.1", 30 | "copy-webpack-plugin": "^4.0.1", 31 | "css-loader": "^0.28.0", 32 | "eslint": "^3.19.0", 33 | "eslint-friendly-formatter": "^3.0.0", 34 | "eslint-loader": "^1.7.1", 35 | "eslint-plugin-html": "^3.0.0", 36 | "eslint-config-standard": "^10.2.1", 37 | "eslint-plugin-promise": "^3.4.0", 38 | "eslint-plugin-standard": "^3.0.1", 39 | "eslint-plugin-import": "^2.7.0", 40 | "eslint-plugin-node": "^5.2.0", 41 | "eventsource-polyfill": "^0.9.6", 42 | "extract-text-webpack-plugin": "^3.0.0", 43 | "file-loader": "^1.1.4", 44 | "friendly-errors-webpack-plugin": "^1.6.1", 45 | "html-webpack-plugin": "^2.30.1", 46 | "webpack-bundle-analyzer": "^2.9.0", 47 | "node-notifier": "^5.1.2", 48 | "postcss-import": "^11.0.0", 49 | "postcss-loader": "^2.0.8", 50 | "semver": "^5.3.0", 51 | "shelljs": "^0.7.6", 52 | "optimize-css-assets-webpack-plugin": "^3.2.0", 53 | "ora": "^1.2.0", 54 | "rimraf": "^2.6.0", 55 | "url-loader": "^0.5.8", 56 | "vue-loader": "^13.3.0", 57 | "vue-style-loader": "^3.0.1", 58 | "vue-template-compiler": "^2.5.2", 59 | "portfinder": "^1.0.13", 60 | "webpack": "^3.6.0", 61 | "webpack-dev-server": "^2.9.1", 62 | "webpack-merge": "^4.1.0" 63 | }, 64 | "engines": { 65 | "node": ">= 4.0.0", 66 | "npm": ">= 3.0.0" 67 | }, 68 | "browserslist": [ 69 | "> 1%", 70 | "last 2 versions", 71 | "not ie <= 8" 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /sidebar/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | 23 | 35 | 36 | 46 | -------------------------------------------------------------------------------- /sidebar/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/sidebar/src/assets/logo.png -------------------------------------------------------------------------------- /sidebar/src/components/sidebar.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 31 | 32 | -------------------------------------------------------------------------------- /sidebar/src/components/sidebarToggle.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | 26 | -------------------------------------------------------------------------------- /sidebar/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import store from './store/index.js' 6 | 7 | Vue.config.productionTip = false 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#app', 12 | store, 13 | template: '', 14 | components: { App } 15 | }) 16 | -------------------------------------------------------------------------------- /sidebar/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import ui from './modules/ui' 4 | 5 | Vue.use(Vuex) 6 | 7 | const debug = process.env.NODE_ENV !== 'production' 8 | 9 | export default new Vuex.Store({ 10 | modules: { 11 | ui 12 | }, 13 | strict: debug 14 | }) 15 | -------------------------------------------------------------------------------- /sidebar/src/store/modules/ui.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | 3 | // initial state 4 | // shape: [{ id, quantity }] 5 | const state = { 6 | sidebarOpen: false 7 | } 8 | 9 | // getters 10 | const getters = { 11 | sidebarOpen: state => state.sidebarOpen 12 | } 13 | 14 | // actions 15 | const actions = { 16 | toggleSidebar ({ commit, state }) { 17 | commit(types.TOGGLE_SIDEBAR) 18 | } 19 | } 20 | 21 | // mutations 22 | const mutations = { 23 | [types.TOGGLE_SIDEBAR] (state) { 24 | state.sidebarOpen = !state.sidebarOpen 25 | } 26 | } 27 | 28 | export default { 29 | state, 30 | getters, 31 | actions, 32 | mutations 33 | } 34 | -------------------------------------------------------------------------------- /sidebar/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const TOGGLE_SIDEBAR = 'TOGGLE_SIDEBAR' 2 | -------------------------------------------------------------------------------- /sidebar/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/sidebar/static/.gitkeep -------------------------------------------------------------------------------- /thumbnail-creator/.serverless/cloudformation-template-create-stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "The AWS CloudFormation template for this Serverless application", 4 | "Resources": { 5 | "ServerlessDeploymentBucket": { 6 | "Type": "AWS::S3::Bucket" 7 | } 8 | }, 9 | "Outputs": { 10 | "ServerlessDeploymentBucketName": { 11 | "Value": { 12 | "Ref": "ServerlessDeploymentBucket" 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /thumbnail-creator/.serverless/thumbnail-creator.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/thumbnail-creator/.serverless/thumbnail-creator.zip -------------------------------------------------------------------------------- /thumbnail-creator/README.md: -------------------------------------------------------------------------------- 1 | # Thumbnail Creator 2 | 3 | A simple web application that uploads files to an S3 bucket and generates thumbnails using AWS Lambda. 4 | 5 | ## Articles on Medium 6 | 7 | *READ THESE FIRST* 8 | 9 | [Part 1 - The Setup](https://medium.com/@rmmmsy/creating-an-image-thumbnail-generator-using-vue-aws-and-serverless-part-1-the-setup-5d187b0bb1e1) 10 | 11 | [Part 2 - The Upload](https://medium.com/@rmmmsy/creating-an-image-thumbnail-generator-using-vue-aws-and-serverless-part-2-the-upload-614863e7d12b) 12 | 13 | [Part 3 - The Lambda](https://medium.com/@rmmmsy/creating-an-image-thumbnail-generator-using-vue-aws-and-serverless-part-3-the-lambda-f08db7d0d624) 14 | 15 | [Part 4 - The Finish](https://medium.com/@rmmmsy/creating-an-image-thumbnail-generator-using-vue-aws-and-serverless-part-4-the-finish-1988eff2d7ed) 16 | 17 | ## Things to note 18 | 19 | ### Serverless.yml 20 | 21 | Please make sure you change the bucket names in the `serverless.yml` file or else you'll have a bad time. 22 | 23 | ### Testing the lambda 24 | 25 | Please read [Part 3 - The Lambda](https://medium.com/@rmmmsy/creating-an-image-thumbnail-generator-using-vue-aws-and-serverless-part-3-the-lambda-f08db7d0d624) carefully when it comes to testing your lambda function. You'll need to have Docker installed. Just read the story, okay?! 26 | 27 | 28 | ### Bugs 29 | 30 | I'm sure there are some - create an issue and be nice. 31 | -------------------------------------------------------------------------------- /thumbnail-creator/client/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"] 9 | } 10 | -------------------------------------------------------------------------------- /thumbnail-creator/client/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /thumbnail-creator/client/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | -------------------------------------------------------------------------------- /thumbnail-creator/client/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | 'rules': { 20 | // allow paren-less arrow functions 21 | 'arrow-parens': 0, 22 | // allow async-await 23 | 'generator-star-spacing': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /thumbnail-creator/client/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /thumbnail-creator/client/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /thumbnail-creator/client/README.md: -------------------------------------------------------------------------------- 1 | # client 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /thumbnail-creator/client/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /thumbnail-creator/client/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /thumbnail-creator/client/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/thumbnail-creator/client/build/logo.png -------------------------------------------------------------------------------- /thumbnail-creator/client/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const pkg = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | return path.posix.join(assetsSubDirectory, _path) 12 | } 13 | 14 | exports.cssLoaders = function (options) { 15 | options = options || {} 16 | 17 | const cssLoader = { 18 | loader: 'css-loader', 19 | options: { 20 | sourceMap: options.sourceMap 21 | } 22 | } 23 | 24 | var postcssLoader = { 25 | loader: 'postcss-loader', 26 | options: { 27 | sourceMap: options.sourceMap 28 | } 29 | } 30 | 31 | // generate loader string to be used with extract text plugin 32 | function generateLoaders (loader, loaderOptions) { 33 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 34 | if (loader) { 35 | loaders.push({ 36 | loader: loader + '-loader', 37 | options: Object.assign({}, loaderOptions, { 38 | sourceMap: options.sourceMap 39 | }) 40 | }) 41 | } 42 | 43 | // Extract CSS when that option is specified 44 | // (which is the case during production build) 45 | if (options.extract) { 46 | return ExtractTextPlugin.extract({ 47 | use: loaders, 48 | fallback: 'vue-style-loader' 49 | }) 50 | } else { 51 | return ['vue-style-loader'].concat(loaders) 52 | } 53 | } 54 | 55 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 56 | return { 57 | css: generateLoaders(), 58 | postcss: generateLoaders(), 59 | less: generateLoaders('less'), 60 | sass: generateLoaders('sass', { indentedSyntax: true }), 61 | scss: generateLoaders('sass'), 62 | stylus: generateLoaders('stylus'), 63 | styl: generateLoaders('stylus') 64 | } 65 | } 66 | 67 | // Generate loaders for standalone style files (outside of .vue) 68 | exports.styleLoaders = function (options) { 69 | const output = [] 70 | const loaders = exports.cssLoaders(options) 71 | for (const extension in loaders) { 72 | const loader = loaders[extension] 73 | output.push({ 74 | test: new RegExp('\\.' + extension + '$'), 75 | use: loader 76 | }) 77 | } 78 | return output 79 | } 80 | 81 | exports.createNotifierCallback = function () { 82 | const notifier = require('node-notifier') 83 | 84 | return (severity, errors) => { 85 | if (severity !== 'error') { 86 | return 87 | } 88 | const error = errors[0] 89 | 90 | const filename = error.file && error.file.split('!').pop() 91 | notifier.notify({ 92 | title: pkg.name, 93 | message: severity + ': ' + error.name, 94 | subtitle: filename || '', 95 | icon: path.join(__dirname, 'logo.png') 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /thumbnail-creator/client/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | 10 | module.exports = { 11 | loaders: utils.cssLoaders({ 12 | sourceMap: sourceMapEnabled, 13 | extract: isProduction 14 | }), 15 | cssSourceMap: sourceMapEnabled, 16 | cacheBusting: config.dev.cacheBusting, 17 | transformToRequire: { 18 | video: 'src', 19 | source: 'src', 20 | img: 'src', 21 | image: 'xlink:href' 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /thumbnail-creator/client/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const Config = require('config') 6 | const fs = require('fs') 7 | const vueLoaderConfig = require('./vue-loader.conf') 8 | 9 | fs.writeFileSync(path.resolve(__dirname, '../config/client.json'), JSON.stringify(Config)) 10 | 11 | function resolve (dir) { 12 | return path.join(__dirname, '..', dir) 13 | } 14 | 15 | module.exports = { 16 | entry: { 17 | app: './src/main.js' 18 | }, 19 | output: { 20 | path: config.build.assetsRoot, 21 | filename: '[name].js', 22 | publicPath: process.env.NODE_ENV === 'production' 23 | ? config.build.assetsPublicPath 24 | : config.dev.assetsPublicPath 25 | }, 26 | resolve: { 27 | extensions: ['.js', '.vue', '.json'], 28 | alias: { 29 | 'vue$': 'vue/dist/vue.esm.js', 30 | '@': resolve('src'), 31 | 'config': resolve('config/client.json') 32 | } 33 | }, 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.(js|vue)$/, 38 | loader: 'eslint-loader', 39 | enforce: 'pre', 40 | include: [resolve('src'), resolve('test')], 41 | options: { 42 | formatter: require('eslint-friendly-formatter') 43 | } 44 | }, 45 | { 46 | test: /\.vue$/, 47 | loader: 'vue-loader', 48 | options: vueLoaderConfig 49 | }, 50 | { 51 | test: /\.js$/, 52 | loader: 'babel-loader', 53 | include: [resolve('src'), resolve('test')] 54 | }, 55 | { 56 | test: /\.(graphql|gql)$/, 57 | exclude: /node_modules/, 58 | use: { 59 | loader: 'graphql-tag/loader' 60 | } 61 | }, 62 | { 63 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 64 | loader: 'url-loader', 65 | options: { 66 | limit: 10000, 67 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 68 | } 69 | }, 70 | { 71 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 72 | loader: 'url-loader', 73 | options: { 74 | limit: 10000, 75 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 76 | } 77 | }, 78 | { 79 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 80 | loader: 'url-loader', 81 | options: { 82 | limit: 10000, 83 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 84 | } 85 | } 86 | ] 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /thumbnail-creator/client/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const portfinder = require('portfinder') 10 | 11 | const devWebpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 14 | }, 15 | // cheap-module-eval-source-map is faster for development 16 | devtool: config.dev.devtool, 17 | 18 | // these devServer options should be customized in /config/index.js 19 | devServer: { 20 | clientLogLevel: 'warning', 21 | historyApiFallback: true, 22 | hot: true, 23 | compress: true, 24 | host: process.env.HOST || config.dev.host, 25 | port: process.env.PORT || config.dev.port, 26 | open: config.dev.autoOpenBrowser, 27 | overlay: config.dev.errorOverlay ? { 28 | warnings: false, 29 | errors: true, 30 | } : false, 31 | publicPath: config.dev.assetsPublicPath, 32 | proxy: config.dev.proxyTable, 33 | quiet: true, // necessary for FriendlyErrorsPlugin 34 | watchOptions: { 35 | poll: config.dev.poll, 36 | } 37 | }, 38 | plugins: [ 39 | new webpack.DefinePlugin({ 40 | 'process.env': require('../config/dev.env') 41 | }), 42 | new webpack.HotModuleReplacementPlugin(), 43 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 44 | new webpack.NoEmitOnErrorsPlugin(), 45 | // https://github.com/ampedandwired/html-webpack-plugin 46 | new HtmlWebpackPlugin({ 47 | filename: 'index.html', 48 | template: 'index.html', 49 | inject: true 50 | }), 51 | ] 52 | }) 53 | 54 | module.exports = new Promise((resolve, reject) => { 55 | portfinder.basePort = process.env.PORT || config.dev.port 56 | portfinder.getPort((err, port) => { 57 | if (err) { 58 | reject(err) 59 | } else { 60 | // publish the new Port, necessary for e2e tests 61 | process.env.PORT = port 62 | // add port to devServer config 63 | devWebpackConfig.devServer.port = port 64 | 65 | // Add FriendlyErrorsPlugin 66 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 67 | compilationSuccessInfo: { 68 | messages: [`Your application is running here: http://${config.dev.host}:${port}`], 69 | }, 70 | onErrors: config.dev.notifyOnErrors 71 | ? utils.createNotifierCallback() 72 | : undefined 73 | })) 74 | 75 | resolve(devWebpackConfig) 76 | } 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /thumbnail-creator/client/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /thumbnail-creator/client/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.4 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | // Template for index.html 53 | index: path.resolve(__dirname, '../dist/index.html'), 54 | 55 | // Paths 56 | assetsRoot: path.resolve(__dirname, '../dist'), 57 | assetsSubDirectory: 'static', 58 | assetsPublicPath: '/', 59 | 60 | /** 61 | * Source Maps 62 | */ 63 | 64 | productionSourceMap: true, 65 | // https://webpack.js.org/configuration/devtool/#production 66 | devtool: '#source-map', 67 | 68 | // Gzip off by default as many popular static hosts such as 69 | // Surge or Netlify already gzip all static assets for you. 70 | // Before setting to `true`, make sure to: 71 | // npm install --save-dev compression-webpack-plugin 72 | productionGzip: false, 73 | productionGzipExtensions: ['js', 'css'], 74 | 75 | // Run the build command with an extra argument to 76 | // View the bundle analyzer report after build finishes: 77 | // `npm run build --report` 78 | // Set to `true` or `false` to always turn it on or off 79 | bundleAnalyzerReport: process.env.npm_config_report 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /thumbnail-creator/client/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /thumbnail-creator/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | client 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /thumbnail-creator/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "lint": "eslint --ext .js,.vue src", 11 | "build": "node build/build.js", 12 | "deploy": "npm run build && aws s3 sync dist/ s3://thumbnail-creator-tutorial" 13 | }, 14 | "dependencies": { 15 | "aws-sdk": "^2.157.0", 16 | "config": "^1.28.1", 17 | "vue": "^2.5.2", 18 | "vue-router": "^3.0.1" 19 | }, 20 | "devDependencies": { 21 | "autoprefixer": "^7.1.2", 22 | "babel-core": "^6.22.1", 23 | "babel-eslint": "^7.1.1", 24 | "babel-loader": "^7.1.1", 25 | "babel-plugin-transform-runtime": "^6.22.0", 26 | "babel-preset-env": "^1.3.2", 27 | "babel-preset-stage-2": "^6.22.0", 28 | "babel-register": "^6.22.0", 29 | "chalk": "^2.0.1", 30 | "copy-webpack-plugin": "^4.0.1", 31 | "css-loader": "^0.28.0", 32 | "eslint": "^3.19.0", 33 | "eslint-friendly-formatter": "^3.0.0", 34 | "eslint-loader": "^1.7.1", 35 | "eslint-plugin-html": "^3.0.0", 36 | "eslint-config-standard": "^10.2.1", 37 | "eslint-plugin-promise": "^3.4.0", 38 | "eslint-plugin-standard": "^3.0.1", 39 | "eslint-plugin-import": "^2.7.0", 40 | "eslint-plugin-node": "^5.2.0", 41 | "eventsource-polyfill": "^0.9.6", 42 | "extract-text-webpack-plugin": "^3.0.0", 43 | "file-loader": "^1.1.4", 44 | "friendly-errors-webpack-plugin": "^1.6.1", 45 | "html-webpack-plugin": "^2.30.1", 46 | "webpack-bundle-analyzer": "^2.9.0", 47 | "node-notifier": "^5.1.2", 48 | "postcss-import": "^11.0.0", 49 | "postcss-loader": "^2.0.8", 50 | "semver": "^5.3.0", 51 | "shelljs": "^0.7.6", 52 | "optimize-css-assets-webpack-plugin": "^3.2.0", 53 | "ora": "^1.2.0", 54 | "rimraf": "^2.6.0", 55 | "url-loader": "^0.5.8", 56 | "vue-loader": "^13.3.0", 57 | "vue-style-loader": "^3.0.1", 58 | "vue-template-compiler": "^2.5.2", 59 | "portfinder": "^1.0.13", 60 | "webpack": "^3.6.0", 61 | "webpack-dev-server": "^2.9.1", 62 | "webpack-merge": "^4.1.0" 63 | }, 64 | "engines": { 65 | "node": ">= 4.0.0", 66 | "npm": ">= 3.0.0" 67 | }, 68 | "browserslist": [ 69 | "> 1%", 70 | "last 2 versions", 71 | "not ie <= 8" 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 20 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/thumbnail-creator/client/src/assets/logo.png -------------------------------------------------------------------------------- /thumbnail-creator/client/src/aws.js: -------------------------------------------------------------------------------- 1 | import {config, S3} from 'aws-sdk' 2 | import {aws} from 'config' 3 | import {map} from 'lodash' 4 | 5 | // Remember to add the name of your thumbnail bucket to the config file 6 | const {region, accessKeyId, secretAccessKey, uploadBucket, thumbnailBucket} = aws 7 | 8 | config.update({ 9 | region: region, 10 | credentials: { 11 | accessKeyId: accessKeyId, 12 | secretAccessKey: secretAccessKey 13 | } 14 | }) 15 | 16 | config.setPromisesDependency(Promise) 17 | 18 | export const s3UploadBucket = new S3({ 19 | apiVersion: '2006-03-01', 20 | params: { 21 | Bucket: uploadBucket 22 | } 23 | }) 24 | 25 | // We create a new S3 object for the thumbnail bucket. 26 | export const s3ThumbnailBucket = new S3({ 27 | apiVersion: '2006-03-01', 28 | params: { 29 | Bucket: thumbnailBucket 30 | } 31 | }) 32 | 33 | export const uploadFiles = files => { 34 | return Promise.all( 35 | map(files, file => { 36 | return s3UploadBucket.putObject({ 37 | Key: file.name, 38 | Body: file 39 | }).promise() 40 | }) 41 | ) 42 | } 43 | 44 | export const getUploads = () => { 45 | return s3UploadBucket.listObjects().promise().then(r => { 46 | return r.Contents 47 | }) 48 | } 49 | 50 | // We use the Prefix option with a value of the key argument. The key 51 | // is the name of the uploaded file without the file extension. 52 | export const getThumbnails = (key) => { 53 | return s3ThumbnailBucket.listObjects({ 54 | Prefix: key 55 | }).promise().then(r => { 56 | return r.Contents 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/components/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 29 | 30 | 36 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/components/appHeader.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/components/list.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 50 | 51 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/components/upload.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | 35 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/components/uploadForm.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 52 | 53 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | 7 | Vue.config.productionTip = false 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#app', 12 | router, 13 | template: '', 14 | components: { App } 15 | }) 16 | -------------------------------------------------------------------------------- /thumbnail-creator/client/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from '@/components/Home' 4 | import Upload from '@/components/upload' 5 | 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '/', 12 | name: 'Home', 13 | component: Home 14 | }, 15 | { 16 | path: '/upload/:key', 17 | name: 'Upload', 18 | component: Upload 19 | } 20 | ] 21 | }) 22 | -------------------------------------------------------------------------------- /thumbnail-creator/client/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/thumbnail-creator/client/static/.gitkeep -------------------------------------------------------------------------------- /thumbnail-creator/handlers/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "Records": [ 3 | { 4 | "s3": { 5 | "bucket":{ 6 | "name":"thumbnail-creator-tutorial-uploads" 7 | }, 8 | "object":{ 9 | "key":"Screen Shot 2017-11-30 at 10.27.47 AM.png" 10 | } 11 | } 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /thumbnail-creator/handlers/transform.js: -------------------------------------------------------------------------------- 1 | const AWS = require('aws-sdk') 2 | const sharp = require('sharp') 3 | const config = require('client/config/production.json') 4 | 5 | AWS.config.update({ 6 | credentials: { 7 | accessKeyId: config.aws.accessKeyId, 8 | secretAccessKey: config.aws.secretAccessKey 9 | } 10 | }) 11 | 12 | AWS.config.setPromisesDependency(Promise) 13 | 14 | const getFileExtension = filename => { 15 | var ext = /^.+\.([^.]+)$/.exec(filename); 16 | return ext == null ? "" : ext[1]; 17 | } 18 | 19 | const s3UploadBucket = new AWS.S3({ 20 | apiVersion: '2006-03-01', 21 | params: { 22 | Bucket: config.aws.uploadBucket 23 | } 24 | }) 25 | 26 | const s3ThumbnailBucket = new AWS.S3({ 27 | apiVersion: '2006-03-01', 28 | params: { 29 | Bucket: config.aws.thumbnailBucket 30 | } 31 | }) 32 | 33 | const transforms = [200, 400, 600] 34 | 35 | module.exports.transform = (event, context, callback) => { 36 | const {key} = event.Records[0].s3.object 37 | 38 | // if you put spaces in your filename, the event Key replaces them with '+'. We need 39 | // to undo that before getting the object. Then we remove the exntesion from the key. 40 | const sanitizedKey = key.replace(/\+/g, ' ') 41 | const keyWithoutExtension = sanitizedKey.replace(/.[^.]+$/, '') 42 | 43 | s3UploadBucket.getObject({Key: sanitizedKey}).promise().then(r => { 44 | transforms.map(t => { 45 | sharp(r.Body) 46 | .resize(t, t) 47 | .max() 48 | .toFormat('jpeg') 49 | .toBuffer() 50 | .then( data => { 51 | s3ThumbnailBucket.putObject({ 52 | Body: data, 53 | Key: `${keyWithoutExtension}-${t}.jpg` 54 | }).promise().then( res => { 55 | console.log(res) 56 | }) 57 | }) 58 | }) 59 | }) 60 | } -------------------------------------------------------------------------------- /thumbnail-creator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "thumbnail-creator", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "test:transform": "docker run -v \"$PWD\":/var/task lambci/lambda:nodejs6.10 handlers/transform.transform \"$(cat handlers/test.json)\"", 9 | "extract:sharp": "tar -xzvf ./sharp/tarballs/sharp-0.18.4-aws-lambda-linux-x64-node-6.10.1.tar.gz -C ./", 10 | "build:sharp": "docker build -t serverless-sharp-image ./sharp && docker run -v \"$PWD/sharp\":/var/task serverless-sharp-image && npm run extract:sharp", 11 | "deploy": "sls deploy -v" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "sharp": "^0.18.4" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /thumbnail-creator/serverless.yml: -------------------------------------------------------------------------------- 1 | service: thumbnail-creator 2 | 3 | custom: 4 | bucket: thumbnail-creator-tutorial 5 | uploadBucket: ${self:custom.bucket}-uploads 6 | thumbnailBucket: ${self:custom.bucket}-thumbnails 7 | 8 | provider: 9 | name: aws 10 | runtime: nodejs6.10 11 | 12 | functions: 13 | transform: 14 | handler: handlers/transform.transform 15 | events: 16 | - s3: 17 | bucket: ${self:custom.uploadBucket} 18 | event: s3:ObjectCreated:* 19 | 20 | resources: 21 | Resources: 22 | UploadBucketS3BucketPolicy: 23 | Type: AWS::S3::BucketPolicy 24 | Properties: 25 | Bucket: 26 | Ref: WebAppS3Bucket 27 | PolicyDocument: 28 | Statement: 29 | - Sid: PublicReadPutObject 30 | Effect: Allow 31 | Principal: "*" 32 | Action: 33 | - s3:PutObject 34 | Resource: arn:aws:s3:::${self:custom.uploadBucket}/* 35 | ThumbnailsS3Bucket: 36 | Type: AWS::S3::Bucket 37 | Properties: 38 | BucketName: ${self:custom.thumbnailBucket} 39 | WebAppS3Bucket: 40 | Type: AWS::S3::Bucket 41 | Properties: 42 | BucketName: ${self:custom.bucket} 43 | AccessControl: PublicRead 44 | WebsiteConfiguration: 45 | IndexDocument: index.html 46 | ErrorDocument: index.html 47 | WebAppS3BucketPolicy: 48 | Type: AWS::S3::BucketPolicy 49 | Properties: 50 | Bucket: 51 | Ref: WebAppS3Bucket 52 | PolicyDocument: 53 | Statement: 54 | - Sid: PublicReadGetObject 55 | Effect: Allow 56 | Principal: "*" 57 | Action: 58 | - s3:GetObject 59 | Resource: arn:aws:s3:::${self:custom.bucket}/* 60 | 61 | package: 62 | exclude: 63 | - client/** 64 | - sharp/** 65 | - package.json 66 | - .serverless 67 | - serverless.yml 68 | include: 69 | - client/config/production.json -------------------------------------------------------------------------------- /thumbnail-creator/sharp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM lambci/lambda:build-nodejs6.10 2 | 3 | CMD ["sh", "/var/task/build.sh"] -------------------------------------------------------------------------------- /thumbnail-creator/sharp/build.sh: -------------------------------------------------------------------------------- 1 | # Set some variables 2 | SHARP_VERSION=$(npm show sharp version) 3 | SHARP_DIRECTORY=sharp-$SHARP_VERSION 4 | TARBALL=sharp-$SHARP_VERSION-aws-lambda-linux-x64-node-6.10.1.tar.gz 5 | 6 | # Make a working directory 7 | mkdir $SHARP_DIRECTORY 8 | cd $SHARP_DIRECTORY 9 | 10 | # NPM install sharp 11 | npm init -y 12 | npm install sharp@$SHARP_VERSION 13 | 14 | # tarball the resulting node_modules 15 | tar --no-xattrs --hard-dereference -cznshf $TARBALL node_modules 16 | 17 | mv $TARBALL ../tarballs 18 | 19 | # Clean up 20 | cd ../ 21 | rm -Rf $SHARP_DIRECTORY 22 | -------------------------------------------------------------------------------- /thumbnail-creator/sharp/tarballs/sharp-0.18.4-aws-lambda-linux-x64-node-6.10.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/thumbnail-creator/sharp/tarballs/sharp-0.18.4-aws-lambda-linux-x64-node-6.10.1.tar.gz -------------------------------------------------------------------------------- /video-colors/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"] 9 | } 10 | -------------------------------------------------------------------------------- /video-colors/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /video-colors/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | -------------------------------------------------------------------------------- /video-colors/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | rules: { 20 | // allow async-await 21 | 'generator-star-spacing': 'off', 22 | // allow debugger during development 23 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /video-colors/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /video-colors/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /video-colors/README.md: -------------------------------------------------------------------------------- 1 | # video-colors 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /video-colors/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /video-colors/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /video-colors/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/video-colors/build/logo.png -------------------------------------------------------------------------------- /video-colors/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const packageConfig = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | 15 | exports.cssLoaders = function (options) { 16 | options = options || {} 17 | 18 | const cssLoader = { 19 | loader: 'css-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | } 24 | 25 | const postcssLoader = { 26 | loader: 'postcss-loader', 27 | options: { 28 | sourceMap: options.sourceMap 29 | } 30 | } 31 | 32 | // generate loader string to be used with extract text plugin 33 | function generateLoaders (loader, loaderOptions) { 34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 35 | 36 | if (loader) { 37 | loaders.push({ 38 | loader: loader + '-loader', 39 | options: Object.assign({}, loaderOptions, { 40 | sourceMap: options.sourceMap 41 | }) 42 | }) 43 | } 44 | 45 | // Extract CSS when that option is specified 46 | // (which is the case during production build) 47 | if (options.extract) { 48 | return ExtractTextPlugin.extract({ 49 | use: loaders, 50 | fallback: 'vue-style-loader' 51 | }) 52 | } else { 53 | return ['vue-style-loader'].concat(loaders) 54 | } 55 | } 56 | 57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 58 | return { 59 | css: generateLoaders(), 60 | postcss: generateLoaders(), 61 | less: generateLoaders('less'), 62 | sass: generateLoaders('sass', { indentedSyntax: true }), 63 | scss: generateLoaders('sass'), 64 | stylus: generateLoaders('stylus'), 65 | styl: generateLoaders('stylus') 66 | } 67 | } 68 | 69 | // Generate loaders for standalone style files (outside of .vue) 70 | exports.styleLoaders = function (options) { 71 | const output = [] 72 | const loaders = exports.cssLoaders(options) 73 | 74 | for (const extension in loaders) { 75 | const loader = loaders[extension] 76 | output.push({ 77 | test: new RegExp('\\.' + extension + '$'), 78 | use: loader 79 | }) 80 | } 81 | 82 | return output 83 | } 84 | 85 | exports.createNotifierCallback = () => { 86 | const notifier = require('node-notifier') 87 | 88 | return (severity, errors) => { 89 | if (severity !== 'error') return 90 | 91 | const error = errors[0] 92 | const filename = error.file && error.file.split('!').pop() 93 | 94 | notifier.notify({ 95 | title: packageConfig.name, 96 | message: severity + ': ' + error.name, 97 | subtitle: filename || '', 98 | icon: path.join(__dirname, 'logo.png') 99 | }) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /video-colors/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /video-colors/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | const createLintingRule = () => ({ 12 | test: /\.(js|vue)$/, 13 | loader: 'eslint-loader', 14 | enforce: 'pre', 15 | include: [resolve('src'), resolve('test')], 16 | options: { 17 | formatter: require('eslint-friendly-formatter'), 18 | emitWarning: !config.dev.showEslintErrorsInOverlay 19 | } 20 | }) 21 | 22 | module.exports = { 23 | context: path.resolve(__dirname, '../'), 24 | entry: { 25 | app: './src/main.js' 26 | }, 27 | output: { 28 | path: config.build.assetsRoot, 29 | filename: '[name].js', 30 | publicPath: process.env.NODE_ENV === 'production' 31 | ? config.build.assetsPublicPath 32 | : config.dev.assetsPublicPath 33 | }, 34 | resolve: { 35 | extensions: ['.js', '.vue', '.json'], 36 | alias: { 37 | 'vue$': 'vue/dist/vue.esm.js', 38 | '@': resolve('src'), 39 | } 40 | }, 41 | module: { 42 | rules: [ 43 | ...(config.dev.useEslint ? [createLintingRule()] : []), 44 | { 45 | test: /\.vue$/, 46 | loader: 'vue-loader', 47 | options: vueLoaderConfig 48 | }, 49 | { 50 | test: /\.js$/, 51 | loader: 'babel-loader', 52 | include: [resolve('src'), resolve('test')] 53 | }, 54 | { 55 | test: /\worker\.js$/, 56 | loader: 'worker-loader', 57 | include: [resolve('src'), resolve('test')] 58 | }, 59 | { 60 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 61 | loader: 'url-loader', 62 | options: { 63 | limit: 10000, 64 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 65 | } 66 | }, 67 | { 68 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 69 | loader: 'url-loader', 70 | options: { 71 | limit: 10000, 72 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 73 | } 74 | }, 75 | { 76 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 77 | loader: 'url-loader', 78 | options: { 79 | limit: 10000, 80 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 81 | } 82 | } 83 | ] 84 | }, 85 | node: { 86 | // prevent webpack from injecting useless setImmediate polyfill because Vue 87 | // source contains it (although only uses it if it's native). 88 | setImmediate: false, 89 | // prevent webpack from injecting mocks to Node native modules 90 | // that does not make sense for the client 91 | dgram: 'empty', 92 | fs: 'empty', 93 | net: 'empty', 94 | tls: 'empty', 95 | child_process: 'empty' 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /video-colors/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const portfinder = require('portfinder') 10 | 11 | const HOST = process.env.HOST 12 | const PORT = process.env.PORT && Number(process.env.PORT) 13 | 14 | const devWebpackConfig = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 17 | }, 18 | // cheap-module-eval-source-map is faster for development 19 | devtool: config.dev.devtool, 20 | 21 | // these devServer options should be customized in /config/index.js 22 | devServer: { 23 | clientLogLevel: 'warning', 24 | historyApiFallback: true, 25 | hot: true, 26 | compress: true, 27 | host: HOST || config.dev.host, 28 | port: PORT || config.dev.port, 29 | open: config.dev.autoOpenBrowser, 30 | overlay: config.dev.errorOverlay 31 | ? { warnings: false, errors: true } 32 | : false, 33 | publicPath: config.dev.assetsPublicPath, 34 | proxy: config.dev.proxyTable, 35 | quiet: true, // necessary for FriendlyErrorsPlugin 36 | watchOptions: { 37 | poll: config.dev.poll, 38 | } 39 | }, 40 | plugins: [ 41 | new webpack.DefinePlugin({ 42 | 'process.env': require('../config/dev.env') 43 | }), 44 | new webpack.HotModuleReplacementPlugin(), 45 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 46 | new webpack.NoEmitOnErrorsPlugin(), 47 | // https://github.com/ampedandwired/html-webpack-plugin 48 | new HtmlWebpackPlugin({ 49 | filename: 'index.html', 50 | template: 'index.html', 51 | inject: true 52 | }), 53 | ] 54 | }) 55 | 56 | module.exports = new Promise((resolve, reject) => { 57 | portfinder.basePort = process.env.PORT || config.dev.port 58 | portfinder.getPort((err, port) => { 59 | if (err) { 60 | reject(err) 61 | } else { 62 | // publish the new Port, necessary for e2e tests 63 | process.env.PORT = port 64 | // add port to devServer config 65 | devWebpackConfig.devServer.port = port 66 | 67 | // Add FriendlyErrorsPlugin 68 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 69 | compilationSuccessInfo: { 70 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 71 | }, 72 | onErrors: config.dev.notifyOnErrors 73 | ? utils.createNotifierCallback() 74 | : undefined 75 | })) 76 | 77 | resolve(devWebpackConfig) 78 | } 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /video-colors/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 13 | 14 | const env = require('../config/prod.env') 15 | 16 | const webpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ 19 | sourceMap: config.build.productionSourceMap, 20 | extract: true, 21 | usePostCSS: true 22 | }) 23 | }, 24 | devtool: config.build.productionSourceMap ? config.build.devtool : false, 25 | output: { 26 | path: config.build.assetsRoot, 27 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 28 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 29 | }, 30 | plugins: [ 31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 32 | new webpack.DefinePlugin({ 33 | 'process.env': env 34 | }), 35 | new UglifyJsPlugin({ 36 | uglifyOptions: { 37 | compress: { 38 | warnings: false 39 | } 40 | }, 41 | sourceMap: config.build.productionSourceMap, 42 | parallel: true 43 | }), 44 | // extract css into its own file 45 | new ExtractTextPlugin({ 46 | filename: utils.assetsPath('css/[name].[contenthash].css'), 47 | // set the following option to `true` if you want to extract CSS from 48 | // codesplit chunks into this main css file as well. 49 | // This will result in *all* of your app's CSS being loaded upfront. 50 | allChunks: false, 51 | }), 52 | // Compress extracted CSS. We are using this plugin so that possible 53 | // duplicated CSS from different components can be deduped. 54 | new OptimizeCSSPlugin({ 55 | cssProcessorOptions: config.build.productionSourceMap 56 | ? { safe: true, map: { inline: false } } 57 | : { safe: true } 58 | }), 59 | // generate dist index.html with correct asset hash for caching. 60 | // you can customize output by editing /index.html 61 | // see https://github.com/ampedandwired/html-webpack-plugin 62 | new HtmlWebpackPlugin({ 63 | filename: config.build.index, 64 | template: 'index.html', 65 | inject: true, 66 | minify: { 67 | removeComments: true, 68 | collapseWhitespace: true, 69 | removeAttributeQuotes: true 70 | // more options: 71 | // https://github.com/kangax/html-minifier#options-quick-reference 72 | }, 73 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 74 | chunksSortMode: 'dependency' 75 | }), 76 | // keep module.id stable when vender modules does not change 77 | new webpack.HashedModuleIdsPlugin(), 78 | // enable scope hoisting 79 | new webpack.optimize.ModuleConcatenationPlugin(), 80 | // split vendor js into its own file 81 | new webpack.optimize.CommonsChunkPlugin({ 82 | name: 'vendor', 83 | minChunks (module) { 84 | // any required modules inside node_modules are extracted to vendor 85 | return ( 86 | module.resource && 87 | /\.js$/.test(module.resource) && 88 | module.resource.indexOf( 89 | path.join(__dirname, '../node_modules') 90 | ) === 0 91 | ) 92 | } 93 | }), 94 | // extract webpack runtime and module manifest to its own file in order to 95 | // prevent vendor hash from being updated whenever app bundle is updated 96 | new webpack.optimize.CommonsChunkPlugin({ 97 | name: 'manifest', 98 | minChunks: Infinity 99 | }), 100 | // This instance extracts shared chunks from code splitted chunks and bundles them 101 | // in a separate chunk, similar to the vendor chunk 102 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 103 | new webpack.optimize.CommonsChunkPlugin({ 104 | name: 'app', 105 | async: 'vendor-async', 106 | children: true, 107 | minChunks: 3 108 | }), 109 | 110 | // copy custom static assets 111 | new CopyWebpackPlugin([ 112 | { 113 | from: path.resolve(__dirname, '../static'), 114 | to: config.build.assetsSubDirectory, 115 | ignore: ['.*'] 116 | } 117 | ]) 118 | ] 119 | }) 120 | 121 | if (config.build.productionGzip) { 122 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 123 | 124 | webpackConfig.plugins.push( 125 | new CompressionWebpackPlugin({ 126 | asset: '[path].gz[query]', 127 | algorithm: 'gzip', 128 | test: new RegExp( 129 | '\\.(' + 130 | config.build.productionGzipExtensions.join('|') + 131 | ')$' 132 | ), 133 | threshold: 10240, 134 | minRatio: 0.8 135 | }) 136 | ) 137 | } 138 | 139 | if (config.build.bundleAnalyzerReport) { 140 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 141 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 142 | } 143 | 144 | module.exports = webpackConfig 145 | -------------------------------------------------------------------------------- /video-colors/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /video-colors/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.5 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | // Template for index.html 53 | index: path.resolve(__dirname, '../dist/index.html'), 54 | 55 | // Paths 56 | assetsRoot: path.resolve(__dirname, '../dist'), 57 | assetsSubDirectory: 'static', 58 | assetsPublicPath: '/', 59 | 60 | /** 61 | * Source Maps 62 | */ 63 | 64 | productionSourceMap: true, 65 | // https://webpack.js.org/configuration/devtool/#production 66 | devtool: '#source-map', 67 | 68 | // Gzip off by default as many popular static hosts such as 69 | // Surge or Netlify already gzip all static assets for you. 70 | // Before setting to `true`, make sure to: 71 | // npm install --save-dev compression-webpack-plugin 72 | productionGzip: false, 73 | productionGzipExtensions: ['js', 'css'], 74 | 75 | // Run the build command with an extra argument to 76 | // View the bundle analyzer report after build finishes: 77 | // `npm run build --report` 78 | // Set to `true` or `false` to always turn it on or off 79 | bundleAnalyzerReport: process.env.npm_config_report 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /video-colors/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /video-colors/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | video-colors 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /video-colors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "video-colors", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "lint": "eslint --ext .js,.vue src", 11 | "build": "node build/build.js" 12 | }, 13 | "dependencies": { 14 | "d3": "^4.12.0", 15 | "vue": "^2.5.2", 16 | "worker-loader": "^1.1.0" 17 | }, 18 | "devDependencies": { 19 | "autoprefixer": "^7.1.2", 20 | "babel-core": "^6.22.1", 21 | "babel-eslint": "^7.1.1", 22 | "babel-loader": "^7.1.1", 23 | "babel-plugin-transform-runtime": "^6.22.0", 24 | "babel-preset-env": "^1.3.2", 25 | "babel-preset-stage-2": "^6.22.0", 26 | "chalk": "^2.0.1", 27 | "copy-webpack-plugin": "^4.0.1", 28 | "css-loader": "^0.28.0", 29 | "eslint": "^3.19.0", 30 | "eslint-config-standard": "^10.2.1", 31 | "eslint-friendly-formatter": "^3.0.0", 32 | "eslint-loader": "^1.7.1", 33 | "eslint-plugin-html": "^3.0.0", 34 | "eslint-plugin-import": "^2.7.0", 35 | "eslint-plugin-node": "^5.2.0", 36 | "eslint-plugin-promise": "^3.4.0", 37 | "eslint-plugin-standard": "^3.0.1", 38 | "eventsource-polyfill": "^0.9.6", 39 | "extract-text-webpack-plugin": "^3.0.0", 40 | "file-loader": "^1.1.4", 41 | "friendly-errors-webpack-plugin": "^1.6.1", 42 | "html-webpack-plugin": "^2.30.1", 43 | "node-notifier": "^5.1.2", 44 | "optimize-css-assets-webpack-plugin": "^3.2.0", 45 | "ora": "^1.2.0", 46 | "portfinder": "^1.0.13", 47 | "postcss-import": "^11.0.0", 48 | "postcss-loader": "^2.0.8", 49 | "rimraf": "^2.6.0", 50 | "semver": "^5.3.0", 51 | "shelljs": "^0.7.6", 52 | "uglifyjs-webpack-plugin": "^1.1.1", 53 | "url-loader": "^0.5.8", 54 | "vue-loader": "^13.3.0", 55 | "vue-style-loader": "^3.0.1", 56 | "vue-template-compiler": "^2.5.2", 57 | "webpack": "^3.6.0", 58 | "webpack-bundle-analyzer": "^2.9.0", 59 | "webpack-dev-server": "^2.9.1", 60 | "webpack-merge": "^4.1.0" 61 | }, 62 | "engines": { 63 | "node": ">= 4.0.0", 64 | "npm": ">= 3.0.0" 65 | }, 66 | "browserslist": [ 67 | "> 1%", 68 | "last 2 versions", 69 | "not ie <= 8" 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /video-colors/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 87 | 88 | 121 | -------------------------------------------------------------------------------- /video-colors/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/video-colors/src/assets/logo.png -------------------------------------------------------------------------------- /video-colors/src/assets/test.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/video-colors/src/assets/test.mp4 -------------------------------------------------------------------------------- /video-colors/src/chart.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 115 | 116 | 122 | -------------------------------------------------------------------------------- /video-colors/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | 6 | Vue.config.productionTip = false 7 | 8 | /* eslint-disable no-new */ 9 | new Vue({ 10 | el: '#app', 11 | template: '', 12 | components: { App } 13 | }) 14 | -------------------------------------------------------------------------------- /video-colors/src/worker.js: -------------------------------------------------------------------------------- 1 | 2 | onmessage = function (e) { 3 | const data = e.data 4 | const BLOCKSIZE = 5 5 | const STEPS = 4 6 | let i = -4 7 | let count = 0 8 | let rgb = {r: 0, g: 0, b: 0} 9 | 10 | let length = data.data.length 11 | while ((i += BLOCKSIZE * STEPS) < length) { 12 | ++count 13 | rgb.r += data.data[i] 14 | rgb.g += data.data[i + 1] 15 | rgb.b += data.data[i + 2] 16 | } 17 | 18 | // ~~ used to floor values 19 | rgb.r = ~~(rgb.r / count) 20 | rgb.g = ~~(rgb.g / count) 21 | rgb.b = ~~(rgb.b / count) 22 | 23 | postMessage(rgb) 24 | } 25 | -------------------------------------------------------------------------------- /video-colors/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramsaylanier/vue-tutorials/26cada54a6f81bc41c0fe786d1d278faf5431e10/video-colors/static/.gitkeep --------------------------------------------------------------------------------