Vue project in real Life
(vue + the tools you need with it for a project)
Summary
- General
- Node/npm
- Linter, babel, wepback
- Vue specific
- Vue-cli and project folder structure
- .vue
- Vue router
- Vuex
Node
(or javascript in the modern world)
javascript everywhere
- Based on V8
- Backend or script tools
- NPM
{
"name": "session2",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^2.6.5",
"vue": "^2.6.10",
"vue-router": "^3.0.3",
"vuex": "^3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.6.0",
"@vue/cli-plugin-eslint": "^3.6.0",
"@vue/cli-service": "^3.6.0",
"@vue/eslint-config-prettier": "^4.0.1",
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"node-sass": "^4.9.0",
"sass-loader": "^7.1.0",
"vue-template-compiler": "^2.5.21"
}
}
package.json
tools
(for more fun)
eslint
prettier
wepback
Babel
webpack
THE bundler
ENTRIES
OUTPUT
app.js
app.js
vue.js
comp.js
comp.css
comp2.js
comp2.scss
image.jpg
....
LOADERS
index.js
style.css
vendor.js
Plugins
LOADERS EXAMPLE
SASS
FILE/URL
SVG
BABEL
json
plugin example
CopyWebpackPlugin
BannerPlugin
SvgSpriteMap
HTMLPlugin
EnvironnementPlugin
import/export
// File a.js
export const myVar = 'toto';
export function myFunc() {
console.log("pouet");
}
// File b.js
import { myVar, myFunc } from './a.js'
console.log(myVar)
myFunc()
// File a2.js
export default function importantFunc() {
console.log("Je suis importante");
}
// File b2.js
import importantFunc from './a2.js'
importantFunc()
// File b2.js
import a2 from './a2.js';
a2();
webpack dev-server
dev best friend
Serve static file during development
Incremental build
Hot Module Reload
VUE-CLI
The config
module.export = {
mode: 'development',
context: '/Users/orwel/valtech/vue-training/session2',
devtool: 'cheap-module-eval-source-map',
node: {
setImmediate: false,
process: 'mock',
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
output: {
path: '/Users/orwel/valtech/vue-training/session2/dist',
filename: '[name].js',
publicPath: '/',
globalObject: 'this'
},
resolve: {
alias: {
'@': '/Users/orwel/valtech/vue-training/session2/src',
vue$: 'vue/dist/vue.runtime.esm.js'
},
extensions: ['.mjs', '.js', '.jsx', '.vue', '.json', '.wasm'],
modules: [
'node_modules',
'/Users/orwel/valtech/vue-training/session2/node_modules',
'/Users/orwel/valtech/vue-training/session2/node_modules/@vue/cli-service/node_modules'
]
},
resolveLoader: {
modules: [
'/Users/orwel/valtech/vue-training/session2/node_modules/@vue/cli-plugin-eslint/node_modules',
'/Users/orwel/valtech/vue-training/session2/node_modules/@vue/cli-plugin-babel/node_modules',
'node_modules',
'/Users/orwel/valtech/vue-training/session2/node_modules',
'/Users/orwel/valtech/vue-training/session2/node_modules/@vue/cli-service/node_modules'
]
},
module: {
noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/,
rules: [
/* config.module.rule('vue') */
{
test: /\.vue$/,
use: [
/* config.module.rule('vue').use('cache-loader') */
{
loader: 'cache-loader',
options: {
cacheDirectory:
'/Users/orwel/valtech/vue-training/session2/node_modules/.cache/vue-loader',
cacheIdentifier: '74b2c360'
}
},
/* config.module.rule('vue').use('vue-loader') */
{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
},
cacheDirectory:
'/Users/orwel/valtech/vue-training/session2/node_modules/.cache/vue-loader',
cacheIdentifier: '74b2c360'
}
}
]
},
/* config.module.rule('images') */
{
test: /\.(png|jpe?g|gif|webp)(\?.*)?$/,
use: [
/* config.module.rule('images').use('url-loader') */
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
]
},
/* config.module.rule('svg') */
{
test: /\.(svg)(\?.*)?$/,
use: [
/* config.module.rule('svg').use('file-loader') */
{
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
]
},
/* config.module.rule('media') */
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [
/* config.module.rule('media').use('url-loader') */
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
]
},
/* config.module.rule('fonts') */
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use: [
/* config.module.rule('fonts').use('url-loader') */
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
}
}
]
},
/* config.module.rule('pug') */
{
test: /\.pug$/,
oneOf: [
/* config.module.rule('pug').oneOf('pug-vue') */
{
resourceQuery: /vue/,
use: [
/* config.module.rule('pug').oneOf('pug-vue').use('pug-plain-loader') */
{
loader: 'pug-plain-loader'
}
]
},
/* config.module.rule('pug').oneOf('pug-template') */
{
use: [
/* config.module.rule('pug').oneOf('pug-template').use('raw') */
{
loader: 'raw-loader'
},
/* config.module.rule('pug').oneOf('pug-template').use('pug-plain') */
{
loader: 'pug-plain-loader'
}
]
}
]
},
/* config.module.rule('css') */
{
test: /\.css$/,
oneOf: [
/* config.module.rule('css').oneOf('vue-modules') */
{
resourceQuery: /module/,
use: [
/* config.module.rule('css').oneOf('vue-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('css').oneOf('vue-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('css').oneOf('vue-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('css').oneOf('vue') */
{
resourceQuery: /\?vue/,
use: [
/* config.module.rule('css').oneOf('vue').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('css').oneOf('vue').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('css').oneOf('vue').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('css').oneOf('normal-modules') */
{
test: /\.module\.\w+$/,
use: [
/* config.module.rule('css').oneOf('normal-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('css').oneOf('normal-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('css').oneOf('normal-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('css').oneOf('normal') */
{
use: [
/* config.module.rule('css').oneOf('normal').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('css').oneOf('normal').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('css').oneOf('normal').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
}
]
},
/* config.module.rule('postcss') */
{
test: /\.p(ost)?css$/,
oneOf: [
/* config.module.rule('postcss').oneOf('vue-modules') */
{
resourceQuery: /module/,
use: [
/* config.module.rule('postcss').oneOf('vue-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('postcss').oneOf('vue-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('postcss').oneOf('vue-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('postcss').oneOf('vue') */
{
resourceQuery: /\?vue/,
use: [
/* config.module.rule('postcss').oneOf('vue').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('postcss').oneOf('vue').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('postcss').oneOf('vue').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('postcss').oneOf('normal-modules') */
{
test: /\.module\.\w+$/,
use: [
/* config.module.rule('postcss').oneOf('normal-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('postcss').oneOf('normal-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('postcss').oneOf('normal-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('postcss').oneOf('normal') */
{
use: [
/* config.module.rule('postcss').oneOf('normal').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('postcss').oneOf('normal').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('postcss').oneOf('normal').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
}
]
}
]
},
/* config.module.rule('scss') */
{
test: /\.scss$/,
oneOf: [
/* config.module.rule('scss').oneOf('vue-modules') */
{
resourceQuery: /module/,
use: [
/* config.module.rule('scss').oneOf('vue-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('scss').oneOf('vue-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('scss').oneOf('vue-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('scss').oneOf('vue-modules').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('scss').oneOf('vue') */
{
resourceQuery: /\?vue/,
use: [
/* config.module.rule('scss').oneOf('vue').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('scss').oneOf('vue').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('scss').oneOf('vue').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('scss').oneOf('vue').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('scss').oneOf('normal-modules') */
{
test: /\.module\.\w+$/,
use: [
/* config.module.rule('scss').oneOf('normal-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('scss').oneOf('normal-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('scss').oneOf('normal-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('scss').oneOf('normal-modules').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('scss').oneOf('normal') */
{
use: [
/* config.module.rule('scss').oneOf('normal').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('scss').oneOf('normal').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('scss').oneOf('normal').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('scss').oneOf('normal').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false
}
}
]
}
]
},
/* config.module.rule('sass') */
{
test: /\.sass$/,
oneOf: [
/* config.module.rule('sass').oneOf('vue-modules') */
{
resourceQuery: /module/,
use: [
/* config.module.rule('sass').oneOf('vue-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('sass').oneOf('vue-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('sass').oneOf('vue-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('sass').oneOf('vue-modules').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false,
indentedSyntax: true
}
}
]
},
/* config.module.rule('sass').oneOf('vue') */
{
resourceQuery: /\?vue/,
use: [
/* config.module.rule('sass').oneOf('vue').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('sass').oneOf('vue').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('sass').oneOf('vue').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('sass').oneOf('vue').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false,
indentedSyntax: true
}
}
]
},
/* config.module.rule('sass').oneOf('normal-modules') */
{
test: /\.module\.\w+$/,
use: [
/* config.module.rule('sass').oneOf('normal-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('sass').oneOf('normal-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('sass').oneOf('normal-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('sass').oneOf('normal-modules').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false,
indentedSyntax: true
}
}
]
},
/* config.module.rule('sass').oneOf('normal') */
{
use: [
/* config.module.rule('sass').oneOf('normal').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('sass').oneOf('normal').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('sass').oneOf('normal').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('sass').oneOf('normal').use('sass-loader') */
{
loader: 'sass-loader',
options: {
sourceMap: false,
indentedSyntax: true
}
}
]
}
]
},
/* config.module.rule('less') */
{
test: /\.less$/,
oneOf: [
/* config.module.rule('less').oneOf('vue-modules') */
{
resourceQuery: /module/,
use: [
/* config.module.rule('less').oneOf('vue-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('less').oneOf('vue-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('less').oneOf('vue-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('less').oneOf('vue-modules').use('less-loader') */
{
loader: 'less-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('less').oneOf('vue') */
{
resourceQuery: /\?vue/,
use: [
/* config.module.rule('less').oneOf('vue').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('less').oneOf('vue').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('less').oneOf('vue').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('less').oneOf('vue').use('less-loader') */
{
loader: 'less-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('less').oneOf('normal-modules') */
{
test: /\.module\.\w+$/,
use: [
/* config.module.rule('less').oneOf('normal-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('less').oneOf('normal-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('less').oneOf('normal-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('less').oneOf('normal-modules').use('less-loader') */
{
loader: 'less-loader',
options: {
sourceMap: false
}
}
]
},
/* config.module.rule('less').oneOf('normal') */
{
use: [
/* config.module.rule('less').oneOf('normal').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('less').oneOf('normal').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('less').oneOf('normal').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('less').oneOf('normal').use('less-loader') */
{
loader: 'less-loader',
options: {
sourceMap: false
}
}
]
}
]
},
/* config.module.rule('stylus') */
{
test: /\.styl(us)?$/,
oneOf: [
/* config.module.rule('stylus').oneOf('vue-modules') */
{
resourceQuery: /module/,
use: [
/* config.module.rule('stylus').oneOf('vue-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('stylus').oneOf('vue-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('stylus').oneOf('vue-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('stylus').oneOf('vue-modules').use('stylus-loader') */
{
loader: 'stylus-loader',
options: {
sourceMap: false,
preferPathResolver: 'webpack'
}
}
]
},
/* config.module.rule('stylus').oneOf('vue') */
{
resourceQuery: /\?vue/,
use: [
/* config.module.rule('stylus').oneOf('vue').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('stylus').oneOf('vue').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('stylus').oneOf('vue').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('stylus').oneOf('vue').use('stylus-loader') */
{
loader: 'stylus-loader',
options: {
sourceMap: false,
preferPathResolver: 'webpack'
}
}
]
},
/* config.module.rule('stylus').oneOf('normal-modules') */
{
test: /\.module\.\w+$/,
use: [
/* config.module.rule('stylus').oneOf('normal-modules').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('stylus').oneOf('normal-modules').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
/* config.module.rule('stylus').oneOf('normal-modules').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('stylus').oneOf('normal-modules').use('stylus-loader') */
{
loader: 'stylus-loader',
options: {
sourceMap: false,
preferPathResolver: 'webpack'
}
}
]
},
/* config.module.rule('stylus').oneOf('normal') */
{
use: [
/* config.module.rule('stylus').oneOf('normal').use('vue-style-loader') */
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
/* config.module.rule('stylus').oneOf('normal').use('css-loader') */
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2
}
},
/* config.module.rule('stylus').oneOf('normal').use('postcss-loader') */
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
/* config.module.rule('stylus').oneOf('normal').use('stylus-loader') */
{
loader: 'stylus-loader',
options: {
sourceMap: false,
preferPathResolver: 'webpack'
}
}
]
}
]
},
/* config.module.rule('js') */
{
test: /\.m?jsx?$/,
exclude: [
function() {
/* omitted long function */
}
],
use: [
/* config.module.rule('js').use('cache-loader') */
{
loader: 'cache-loader',
options: {
cacheDirectory:
'/Users/orwel/valtech/vue-training/session2/node_modules/.cache/babel-loader',
cacheIdentifier: '4d0d77df'
}
},
/* config.module.rule('js').use('babel-loader') */
{
loader: 'babel-loader'
}
]
},
/* config.module.rule('eslint') */
{
enforce: 'pre',
test: /\.(vue|(j|t)sx?)$/,
exclude: [
/node_modules/,
'/Users/orwel/valtech/vue-training/session2/node_modules/@vue/cli-service/lib'
],
use: [
/* config.module.rule('eslint').use('eslint-loader') */
{
loader: 'eslint-loader',
options: {
extensions: ['.js', '.jsx', '.vue'],
cache: true,
cacheIdentifier: '2bd8ec35',
emitWarning: true,
emitError: false,
eslintPath:
'/Users/orwel/valtech/vue-training/session2/node_modules/eslint/lib/api.js',
formatter: function() {
/* omitted long function */
}
}
}
]
}
]
},
plugins: [
/* config.plugin('vue-loader') */
new VueLoaderPlugin(),
/* config.plugin('define') */
new DefinePlugin({
'process.env': {
NODE_ENV: '"development"',
BASE_URL: '"/"'
}
}),
/* config.plugin('case-sensitive-paths') */
new CaseSensitivePathsPlugin(),
/* config.plugin('friendly-errors') */
new FriendlyErrorsWebpackPlugin({
additionalTransformers: [
function() {
/* omitted long function */
}
],
additionalFormatters: [
function() {
/* omitted long function */
}
]
}),
/* config.plugin('hmr') */
new HotModuleReplacementPlugin(),
/* config.plugin('progress') */
new ProgressPlugin(),
/* config.plugin('html') */
new HtmlWebpackPlugin({
templateParameters: function() {
/* omitted long function */
},
template: '/Users/orwel/valtech/vue-training/session2/public/index.html'
}),
/* config.plugin('preload') */
new PreloadPlugin({
rel: 'preload',
include: 'initial',
fileBlacklist: [/\.map$/, /hot-update\.js$/]
}),
/* config.plugin('prefetch') */
new PreloadPlugin({
rel: 'prefetch',
include: 'asyncChunks'
}),
/* config.plugin('copy') */
new CopyWebpackPlugin([
{
from: '/Users/orwel/valtech/vue-training/session2/public',
to: '/Users/orwel/valtech/vue-training/session2/dist',
toType: 'dir',
ignore: ['.DS_Store']
}
])
],
entry: {
app: ['./src/main.js']
}
}
KEEP CALM AND TRUST COMMUNITY
npm install -g vue-cli
vue create my-project
pokemon app
use what we have done before
git checkout -b pokemon-app
DEMO
cd session2
npm install
Pendant que je parle, lancez le truc long ...
Add api call
import axios from 'axios'
const dataPromise = axios.get('/my-data-path')
dataPromise.then(data => {
console.log(data)
})
.catch(err => console.log("Something goes wrong"))
// Use inside async function => cleaner synthax
async function getData() {
try {
const data = await axios.get('/my-data-path')
console.log(data)
}
catch (err) {
console.log("Something goes wrong")
}
}
Example
git checkout step-1
Fetch Type information
Vue router
Vue router
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '@/views/Home';
import About from '@/views/About';
Vue.use(VueRouter);
const routes = [{ path: '/', component: Home }, { path: '/about', component: About }];
const router = new VueRouter({
routes,
});
new Vue({
router,
render: h => h(App),
}).$mount('#app');
Vue Router
- rendu à l'intérieur de router-view
- router-link pour naviguer
<template>
<div id="app">
<h1>Mon application avec du routage</h1>
<div style="border: 1px solid red;padding:1em">
<router-view></router-view>
</div>
</div>
</template>
<nav>
<router-link to="/">Homepage</router-link>
<router-link to="/about">About</router-link>
</nav>
Vue Router
- Parameters
routes: [
{ path: '/type/:name', component: TypePage }
]
// Inside components
this.$route.params // { name: 'fire' }
// $router is also available for programmatic routing
DEMO
git checkout step-2
Session 3
git checkout session3
cd session3
npm install
Vue SLOTS
SLOTS
Let the parent define a part of the child component template
// Page component
<Article title="Article 1">
<p>Blabla ...</p>
<p>Blabababa</p>
</Article>
// Article components
<div class="article">
<h2>{{title}}</h2>
<div class="article_content">
<slot></slot>
</div>
</div>
demo
several slots
// Article components
<div class="article">
<div class="article_header">
<slot name="header"></slot>
</div>
<div class="article_content">
<slot></slot>
</div>
</div>
// Page component
<Article title="Article 1">
<template v-slot="header"></template>
<p>Blabla ...</p>
<p>Blabababa</p>
</Article>
demo
git checkout slots
Vuex
The problem
Vuex
Store
Vuex-state
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
user: { name: 'Jean-Michel' }
}
})
new Vue({
store,
render: h => h(App),
}).$mount('#app');
// Composant.vue
this.$store.state.user
Vuex-mutations
const store = new Vuex.Store({
state: {
todos: []
},
mutations: {
addTodos(state, task) {
state.todos.push(item)
}
}
})
// Inside components
this.$store.commit('addTodos', 'Finish Pokemons app')
Vuex-getters
const store = new Vuex.Store({
state: {
todos: []
},
getters: {
todoCount(state) {
return this.todos.length
}
}
})
// Inside components
this.$store.getters.todoCount
demo
git checkout store
Mutations => synchronous
asynchronous ?
ACTIONS !
Vuex-ACTIONS
const store = new Vuex.Store({
state: {
todos: []
},
mutations: {
addTodos(state, task) {
state.todos.push(item)
}
}
actions: {
async add(context, task) {
await axios.post('/add', task)
context.commit('addTodos', task)
}
}
})
// Inside components
this.$store.dispatch('add', 'Finish Pokemons app')
et les props?
tout dépends des cas !
demo
git checkout store-actions
npm install
node server/server.js
npm run serve
Let's move outside
- Créer une page OutsidePage (avec routing)
- Afficher le composant Map à l'intérieur
- Ajouter le composant Controls
- Modifier le composant Controls pour bouger le personnage
- Modifier le composant Controls pour aller sur la homepage au clic sur start, et dans le pokédex au clic sur select
catch-up
git checkout adventure-1
let's always have a friend
- Ajouter un getter dans le store pour savoir si un combat est en cours (isFighting)
- Ajouter un getter dans le store pour savoir si on est actuellement dans les hautes herbes (isOnHighGrass)
- Désactiver les mouvements d'équipe en combat
- Empêcher de retirer le dernier pokémon de la ceinture si on est dans les hautes herbes
catch-up
git checkout adventure-2
let's fight
- Ajouter un composant Fight, et afficher le à la place de la map lorsqu'on est en combat
- Afficher notre pokémon de dos, et l'autre pokémon de face dans ce combat
- Ajouter une mutation flee dans le store qui permet de fuir le combat
- Ajouter un bouton "Fuir" dans le composant fight
- Afficher à l'écran si on possède déjà le pokémon ou pas
catch-up
git checkout adventure-3
let's capture them all
- Ajouter une action capturePokemon, qui ajoute le Pokémon sauvage dans la ceinture s'il reste de la place, l'envoie dans la box sinon
- Ajouter un bouton "Pokéball", qui s'affiche si on a pas encore le Pokémon et qui permet de capturer le pokémon
Vue training (session2&3)
By Aurélie Violette
Vue training (session2&3)
- 773