Add Skeleton of Vue JS with webpack

This commit is contained in:
2016-03-19 10:51:12 +01:00
parent 446b0b2fb9
commit 0a2ecc1087
26 changed files with 711 additions and 0 deletions

5
src/ui/Domo/.babelrc Normal file
View File

@@ -0,0 +1,5 @@
{
"presets": ["es2015", "stage-2"],
"plugins": ["transform-runtime"],
"comments": false
}

View File

@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

16
src/ui/Domo/.eslintrc.js Normal file
View File

@@ -0,0 +1,16 @@
module.exports = {
root: true,
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}

7
src/ui/Domo/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
.DS_Store
node_modules/
dist/
npm-debug.log
selenium-debug.log
test/unit/coverage
test/e2e/reports

27
src/ui/Domo/README.md Normal file
View File

@@ -0,0 +1,27 @@
# Domo
> Domotic automation
## Build Setup
``` bash
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
# run unit tests
npm run unit
# run e2e tests
npm run e2e
# run all tests
npm test
```
For detailed explanation on how things work, checkout the [guide](https://github.com/vuejs-templates/webpack#vue-webpack-boilerplate) and [docs for vue-loader](http://vuejs.github.io/vue-loader).

View File

@@ -0,0 +1,34 @@
var ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = function (options) {
// generate loader string to be used with extract text plugin
function generateLoaders (loaders) {
var sourceLoader = loaders.map(function (loader) {
var extraParamChar
if (/\?/.test(loader)) {
loader = loader.replace(/\?/, '-loader?')
extraParamChar = '&'
} else {
loader = loader + '-loader'
extraParamChar = '?'
}
return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
}).join('!')
if (options.extract) {
return ExtractTextPlugin.extract('vue-style-loader', sourceLoader)
} else {
return ['vue-style-loader', sourceLoader].join('!')
}
}
// http://vuejs.github.io/vue-loader/configurations/extract-css.html
return {
css: generateLoaders(['css']),
less: generateLoaders(['css', 'less']),
sass: generateLoaders(['css', 'sass?indentedSyntax']),
scss: generateLoaders(['css', 'sass']),
stylus: generateLoaders(['css', 'stylus']),
styl: generateLoaders(['css', 'stylus'])
}
}

View File

@@ -0,0 +1,8 @@
require('eventsource-polyfill')
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
hotClient.subscribe(function (event) {
if (event.action === 'reload') {
window.location.reload()
}
})

View File

@@ -0,0 +1,66 @@
var express = require('express')
var webpack = require('webpack')
var config = require('./webpack.dev.conf')
var proxyMiddleware = require('http-proxy-middleware')
var app = express()
var compiler = webpack(config)
// Define HTTP proxies to your custom API backend
// https://github.com/chimurai/http-proxy-middleware
var proxyTable = {
// '/api': {
// target: 'http://jsonplaceholder.typicode.com',
// changeOrigin: true,
// pathRewrite: {
// '^/api': ''
// }
// }
}
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: config.output.publicPath,
stats: {
colors: true,
chunks: false
}
})
var hotMiddleware = require('webpack-hot-middleware')(compiler)
// force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})
// proxy api requests
Object.keys(proxyTable).forEach(function (context) {
var options = proxyTable[context]
if (typeof options === 'string') {
options = { target: options }
}
app.use(proxyMiddleware(context, options))
})
// handle fallback for HTML5 history API
app.use(require('connect-history-api-fallback')())
// serve webpack bundle output
app.use(devMiddleware)
// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware)
// serve pure static assets
app.use('/static', express.static('./static'))
module.exports = app.listen(8080, function (err) {
if (err) {
console.log(err)
return
}
console.log('Listening at http://localhost:8080')
})

View File

@@ -0,0 +1,77 @@
var path = require('path')
var cssLoaders = require('./css-loaders')
var projectRoot = path.resolve(__dirname, '../')
module.exports = {
entry: {
app: './src/main.js'
},
output: {
path: path.resolve(__dirname, '../dist/static'),
publicPath: '/static/',
filename: '[name].js'
},
resolve: {
extensions: ['', '.js', '.vue'],
fallback: [path.join(__dirname, '../node_modules')],
alias: {
'src': path.resolve(__dirname, '../src')
}
},
resolveLoader: {
fallback: [path.join(__dirname, '../node_modules')]
},
module: {
preLoaders: [
{
test: /\.vue$/,
loader: 'eslint',
include: projectRoot,
exclude: /node_modules/
},
{
test: /\.js$/,
loader: 'eslint',
include: projectRoot,
exclude: /node_modules/
}
],
loaders: [
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.js$/,
loader: 'babel',
include: projectRoot,
exclude: /node_modules/
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.html$/,
loader: 'vue-html'
},
{
test: /\.(png|jpg|gif|svg|woff2?|eot|ttf)(\?.*)?$/,
loader: 'url',
query: {
limit: 10000,
name: '[name].[ext]?[hash:7]'
}
}
]
},
vue: {
loaders: cssLoaders({
sourceMap: false,
extract: false
})
},
eslint: {
formatter: require('eslint-friendly-formatter')
}
}

View File

@@ -0,0 +1,31 @@
var webpack = require('webpack')
var merge = require('webpack-merge')
var baseConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
// add hot-reload related code to entry chunks
Object.keys(baseConfig.entry).forEach(function (name) {
baseConfig.entry[name] = ['./build/dev-client'].concat(baseConfig.entry[name])
})
module.exports = merge(baseConfig, {
// eval-source-map is faster for development
devtool: '#eval-source-map',
output: {
// necessary for the html plugin to work properly
// when serving the html from in-memory
publicPath: '/'
},
plugins: [
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
]
})

View File

@@ -0,0 +1,60 @@
var webpack = require('webpack')
var merge = require('webpack-merge')
var baseConfig = require('./webpack.base.conf')
var cssLoaders = require('./css-loaders')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
// whether to generate source map for production files.
// disabling this can speed up the build.
var SOURCE_MAP = true
module.exports = merge(baseConfig, {
stats: {
children: false
},
devtool: SOURCE_MAP ? '#source-map' : false,
output: {
// naming output files with hashes for better caching.
// dist/index.html will be auto-generated with correct URLs.
filename: '[name].[chunkhash].js',
chunkFilename: '[id].[chunkhash].js'
},
vue: {
loaders: cssLoaders({
sourceMap: SOURCE_MAP,
extract: true
})
},
plugins: [
// http://vuejs.github.io/vue-loader/workflow/production.html
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.optimize.OccurenceOrderPlugin(),
// extract css into its own file
new ExtractTextPlugin('[name].[contenthash].css'),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: '../index.html',
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
}
})
]
})

11
src/ui/Domo/index.html Normal file
View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Domo</title>
</head>
<body>
<app></app>
<!-- built files will be auto injected -->
</body>
</html>

69
src/ui/Domo/package.json Normal file
View File

@@ -0,0 +1,69 @@
{
"name": "Domo",
"version": "0.1.0",
"description": "Domotic automation",
"author": "NADAL Jean-Baptiste",
"private": true,
"scripts": {
"dev": "node build/dev-server.js",
"build": "rimraf dist && mkdirp dist && ncp static dist/static && cross-env NODE_ENV=production webpack --progress --hide-modules --config build/webpack.prod.conf.js",
"unit": "karma start test/unit/karma.conf.js --single-run",
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e"
},
"dependencies": {
"vue": "^1.0.17"
},
"devDependencies": {
"babel-core": "^6.0.0",
"babel-loader": "^6.0.0",
"babel-plugin-transform-runtime": "^6.0.0",
"babel-preset-es2015": "^6.0.0",
"babel-preset-stage-2": "^6.0.0",
"chromedriver": "^2.21.2",
"connect-history-api-fallback": "^1.1.0",
"cross-env": "^1.0.7",
"cross-spawn": "^2.1.5",
"css-loader": "^0.23.0",
"eslint": "^2.0.0",
"eslint-config-standard": "^5.1.0",
"eslint-friendly-formatter": "^1.2.2",
"eslint-loader": "^1.3.0",
"eslint-plugin-html": "^1.3.0",
"eslint-plugin-promise": "^1.0.8",
"eslint-plugin-standard": "^1.3.2",
"eventsource-polyfill": "^0.9.6",
"express": "^4.13.3",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.4",
"function-bind": "^1.0.2",
"html-webpack-plugin": "^2.8.1",
"http-proxy-middleware": "^0.11.0",
"inject-loader": "^2.0.1",
"isparta-loader": "^2.0.0",
"jasmine-core": "^2.4.1",
"json-loader": "^0.5.4",
"karma": "^0.13.15",
"karma-coverage": "^0.5.5",
"karma-jasmine": "^0.3.6",
"karma-phantomjs-launcher": "^1.0.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.24",
"karma-webpack": "^1.7.0",
"mkdirp": "^0.5.1",
"ncp": "^2.0.0",
"nightwatch": "^0.8.18",
"phantomjs-prebuilt": "^2.1.3",
"rimraf": "^2.5.0",
"selenium-server": "2.52.0",
"url-loader": "^0.5.7",
"vue-hot-reload-api": "^1.2.0",
"vue-html-loader": "^1.0.0",
"vue-loader": "^8.2.1",
"vue-style-loader": "^1.0.0",
"webpack": "^1.12.2",
"webpack-dev-middleware": "^1.4.0",
"webpack-hot-middleware": "^2.6.0",
"webpack-merge": "^0.8.3"
}
}

56
src/ui/Domo/src/App.vue Normal file
View File

@@ -0,0 +1,56 @@
<template>
<div id="app">
<img class="logo" src="./assets/logo.png">
<hello></hello>
<p>
Welcome to your Vue.js app. To get started, take a look at the
<a href="https://github.com/vuejs-templates/webpack#folder-structure" target="_blank">README</a>
of this template. If you have any issues with the setup, please file an issue at this template's repository.
</p>
<p>
For advanced configurations, checkout the docs for
<a href="http://webpack.github.io/" target="_blank">Webpack</a> and
<a href="http://vuejs.github.io/vue-loader/" target="_blank">vue-loader</a>.
</p>
<p>
You may also want to checkout
<a href="https://github.com/vuejs/vue-router/" target="_blank">vue-router</a> for routing and
<a href="https://github.com/vuejs/vuex/" target="_blank">vuex</a> for state management.
</p>
</div>
</template>
<script>
import Hello from './components/Hello'
export default {
components: {
Hello
}
}
</script>
<style>
html {
height: 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
#app {
margin-top: -100px;
max-width: 600px;
font-family: Helvetica, sans-serif;
text-align: center;
}
.logo {
width: 100px;
height: 100px
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,19 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
data () {
return {
// note: changing this line won't causes changes
// with hot-reload because the reloaded component
// preserves its current state and we are modifying
// its initial state.
msg: 'Hello World!'
}
}
}
</script>

8
src/ui/Domo/src/main.js Normal file
View File

@@ -0,0 +1,8 @@
import Vue from 'vue'
import App from './App'
/* eslint-disable no-new */
new Vue({
el: 'body',
components: { App }
})

View File

View File

@@ -0,0 +1,26 @@
// A custom Nightwatch assertion.
// the name of the method is the filename.
// can be used in tests like this:
//
// browser.assert.elementCount(selector, count)
//
// for how to write custom assertions see
// http://nightwatchjs.org/guide#writing-custom-assertions
exports.assertion = function (selector, count) {
this.message = 'Testing if element <' + selector + '> has count: ' + count
this.expected = count
this.pass = function (val) {
return val === this.expected
}
this.value = function (res) {
return res.value
}
this.command = function (cb) {
var self = this
return this.api.execute(function (selector) {
return document.querySelectorAll(selector).length
}, [selector], function (res) {
cb.call(self, res)
})
}
}

View File

@@ -0,0 +1,40 @@
// http://nightwatchjs.org/guide#settings-file
module.exports = {
"src_folders": ["test/e2e/specs"],
"output_folder": "test/e2e/reports",
"custom_assertions_path": ["test/e2e/custom-assertions"],
"selenium": {
"start_process": true,
"server_path": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.52.0.jar",
"host": "127.0.0.1",
"port": 4444,
"cli_args": {
"webdriver.chrome.driver": require('chromedriver').path
}
},
"test_settings": {
"default": {
"selenium_port": 4444,
"selenium_host": "localhost",
"silent": true
},
"chrome": {
"desiredCapabilities": {
"browserName": "chrome",
"javascriptEnabled": true,
"acceptSslCerts": true
}
},
"firefox": {
"desiredCapabilities": {
"browserName": "firefox",
"javascriptEnabled": true,
"acceptSslCerts": true
}
}
}
}

View File

@@ -0,0 +1,30 @@
// 1. start the dev server
var server = require('../../build/dev-server.js')
// 2. run the nightwatch test suite against it
// to run in additional browsers:
// 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings"
// 2. add it to the --env flag below
// For more information on Nightwatch's config file, see
// http://nightwatchjs.org/guide#settings-file
var spawn = require('cross-spawn')
var runner = spawn(
'./node_modules/.bin/nightwatch',
[
'--config', 'test/e2e/nightwatch.conf.js',
'--env', 'chrome,firefox'
],
{
stdio: 'inherit'
}
)
runner.on('exit', function (code) {
server.close()
process.exit(code)
})
runner.on('error', function (err) {
server.close()
throw err
})

View File

@@ -0,0 +1,14 @@
// For authoring Nightwatch tests, see
// http://nightwatchjs.org/guide#usage
module.exports = {
'default e2e tests': function (browser) {
browser
.url('http://localhost:8080')
.waitForElementVisible('#app', 5000)
.assert.elementPresent('.logo')
.assert.containsText('h1', 'Hello World!')
.assert.elementCount('p', 3)
.end()
}
}

View File

@@ -0,0 +1,5 @@
{
"env": {
"jasmine": true
}
}

View File

@@ -0,0 +1,13 @@
// Polyfill fn.bind() for PhantomJS
/* eslint-disable no-extend-native */
Function.prototype.bind = require('function-bind')
// require all test files (files that ends with .spec.js)
var testsContext = require.context('./specs', true, /\.spec$/)
testsContext.keys().forEach(testsContext)
// require all src files except main.js for coverage.
// you can also change this to match only the subset of files that
// you want coverage for.
var srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
srcContext.keys().forEach(srcContext)

View File

@@ -0,0 +1,65 @@
// This is a karma config file. For more details see
// http://karma-runner.github.io/0.13/config/configuration-file.html
// we are also using it with karma-webpack
// https://github.com/webpack/karma-webpack
var path = require('path')
var merge = require('webpack-merge')
var baseConfig = require('../../build/webpack.base.conf')
var projectRoot = path.resolve(__dirname, '../../')
var webpackConfig = merge(baseConfig, {
// use inline sourcemap for karma-sourcemap-loader
devtool: '#inline-source-map',
vue: {
loaders: {
js: 'isparta'
}
}
})
// no need for app entry during tests
delete webpackConfig.entry
// make sure isparta loader is applied before eslint
webpackConfig.module.preLoaders.unshift({
test: /\.js$/,
loader: 'isparta',
include: projectRoot,
exclude: /test\/unit|node_modules/
})
// only apply babel for test files when using isparta
webpackConfig.module.loaders.some(function (loader, i) {
if (loader.loader === 'babel') {
loader.include = /test\/unit/
return true
}
})
module.exports = function (config) {
config.set({
// to run in additional browsers:
// 1. install corresponding karma launcher
// http://karma-runner.github.io/0.13/config/browsers.html
// 2. add it to the `browsers` array below.
browsers: ['PhantomJS'],
frameworks: ['jasmine'],
reporters: ['spec', 'coverage'],
files: ['./index.js'],
preprocessors: {
'./index.js': ['webpack', 'sourcemap']
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
coverageReporter: {
dir: './coverage',
reporters: [
{ type: 'lcov', subdir: '.' },
{ type: 'text-summary' }
]
}
})
}

View File

@@ -0,0 +1,15 @@
import Vue from 'vue'
import Hello from 'src/components/Hello'
describe('Hello.vue', () => {
it('should render correct contents', () => {
const vm = new Vue({
template: '<div><hello></hello></div>',
components: { Hello }
}).$mount()
expect(vm.$el.querySelector('.hello h1').textContent).toBe('Hello World!')
})
})
// also see example testing a component with mocks at
// https://github.com/vuejs/vue-loader-example/blob/master/test/unit/a.spec.js#L24-L49