Forráskód Böngészése

adapt to latest vue-cli

Junx 7 éve
szülő
commit
4d446afd54

+ 11 - 3
.babelrc

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

+ 4 - 2
.eslintignore

@@ -1,2 +1,4 @@
-build/*.js
-config/*.js
+/build/
+/config/
+/dist/
+/*.js

+ 8 - 2
.eslintrc.js

@@ -1,10 +1,15 @@
+// https://eslint.org/docs/user-guide/configuring
+
 module.exports = {
   root: true,
   parser: 'babel-eslint',
   parserOptions: {
     sourceType: 'module'
   },
-  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
+  env: {
+    browser: true,
+  },
+  // https://github.com/standard/standard/blob/master/docs/RULES-en.md
   extends: 'standard',
   // required to lint *.vue files
   plugins: [
@@ -21,6 +26,7 @@ module.exports = {
     'semi': ['error', 'always'],
     'no-tabs': 0,
     'indent': 0,
-    'space-before-function-paren': 0
+    'space-before-function-paren': 0,
+    'no-multiple-empty-lines': ["error", { "max": 2, "maxBOF": 1}]
   }
 }

+ 12 - 6
.gitignore

@@ -1,8 +1,14 @@
 .DS_Store
 node_modules/
-dist/
-.idea/
-npm-debug.log
-selenium-debug.log
-test/unit/coverage
-test/e2e/reports
+/dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln

+ 9 - 0
.postcssrc.js

@@ -0,0 +1,9 @@
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  "plugins": {
+    // to edit target browsers: use "browserslist" field in package.json
+    "postcss-import": {},
+    "autoprefixer": {}
+  }
+}

+ 69 - 20
README.md

@@ -1,36 +1,85 @@
 # vue-sell
-Vue.js 高仿饿了么外卖 App 课程源码,课程地址: http://coding.imooc.com/class/74.html
 
-本源码基于 GPL 协议,仅仅用于 Vue 实战项目的学习,不可作为商业用途。
-我们抵制和鄙视一切盗版侵权行为,请尊重作者的劳动果实!
+> A Vue.js project
 
-[项目演示地址](http://ustbhuangyi.com/sell/)
+## Build Setup
 
-![二维码](https://qr.api.cli.im/qr?data=http%253A%252F%252Fustbhuangyi.com%252Fsell%252F%2523%252Fgoods&level=H&transparent=false&bgcolor=%23ffffff&forecolor=%23000000&blockpixel=12&marginblock=1&logourl=&size=280&kid=cliim&key=686203a49c4613080b5b3004323ff977)
+``` bash
+# install dependencies
+npm install
 
-## 你可以学到什么
-我们可以通过一张图来认识一下本课程的知识结构
+# serve with hot reload at localhost:8080
+npm run dev
 
-![vue-sell](https://webapp.didistatic.com/static/webapp/shield/vue-sell.png)
+# build for production with minification
+npm run build
 
-## 如何学习
-请从正规渠道购买本课程的教学视频: http://coding.imooc.com/class/74.html。
-你还可以加入课程讨论群,与同学一起讨论问题,还可以得到我的亲自指导。
+# build for production and view the bundle analyzer report
+npm run build --report
+```
 
-## 适合人群
-适合有一定 Vue.js 和前端基础知识并且想深入学习 Vue.js 并运用在实战项目的同学。
+> 更新内容
 
-## TODO
-~~由于本课程录制时间较早,编写代码的时候 Vue.js 2.0 还未正式发布,所以源码采用 1.0 编写,后续会更新到 2.0 版本。~~
+```
+#1.安装vue-resource  better-scroll
+cnpm install vue-resource better-scroll --save
 
-master 代码已经升级到最新 Vue.js 2.1.10 版本,如果想查看 1.0 版本的代码可以切换到 1.0 的代码分支。
 
-## Vue.js 进阶
+#2.安装stylus stylus-loader 
+cnpm install stylus stylus-loader --save-dev
 
-如果想在 Vue.js 的方向进阶,学习更加复杂的项目开发的同学。可以关注我的新课程:http://coding.imooc.com/class/107.html
 
-[项目演示地址](http://ustbhuangyi.com/music/)
+#3.build目录webpack.base.conf.js   修改alias为
+    {
+        'src': path.resolve(__dirname, '../src'),
+        'common': path.resolve(__dirname, '../src/common'),
+        'components': path.resolve(__dirname, '../src/components')
+    }
 
-![二维码](https://qr.api.cli.im/qr?data=http%253A%252F%252Fustbhuangyi.com%252Fmusic%252F&level=H&transparent=false&bgcolor=%23ffffff&forecolor=%23000000&blockpixel=12&marginblock=1&logourl=&size=280&kid=cliim&key=731bbcc2b490454d2cc604f98539952c)
+#4.修改.eslintrc.js 添加规则
+    'semi': ['error', 'always'],
+    'no-tabs': 0,
+    'indent': 0,
+    'space-before-function-paren': 0
 
 
+
+
+#5.http://eslint.org/docs/rules/no-multiple-empty-lines  Too many blank lines at the end of file. Max of 0 
+
+allowed
+src\App.vue:52:1   App.vue报错
+
+.eslintrc.js 添加规则
+    'no-multiple-empty-lines': ["error", { "max": 2, "maxBOF": 1}]
+
+
+
+#6.修改config目录下的index.js文件
+
+设置代理 
+    proxyTable: {
+            '/api': 'http://localhost:8088'
+        },
+修改host: '0.0.0.0'
+
+
+
+#7.修改dev-server.js文件,现在只负责后端数据的传输
+删除webpack依赖,修改port为8088
+
+
+#8.路由栏     商品 评论 商家   的下划线消失了
+修改App.vue文件样式 .tab 下 将
+border-1px(rgba(7, 17, 27, 0.1))
+移到注释
+//border-bottom: 1px solid rgba(7, 17, 27, 0.1)
+之前
+解决问题
+
+
+#9.从App.vue提取路由 单独放到router的index.js中
+
+```
+
+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).

+ 33 - 28
build/build.js

@@ -1,36 +1,41 @@
-// https://github.com/shelljs/shelljs
+'use strict'
 require('./check-versions')()
-require('shelljs/global')
-env.NODE_ENV = 'production'
 
-var path = require('path')
-var config = require('../config')
-var ora = require('ora')
-var webpack = require('webpack')
-var webpackConfig = require('./webpack.prod.conf')
+process.env.NODE_ENV = 'production'
 
-console.log(
-  '  Tip:\n' +
-  '  Built files are meant to be served over an HTTP server.\n' +
-  '  Opening index.html over file:// won\'t work.\n'
-)
+const ora = require('ora')
+const rm = require('rimraf')
+const path = require('path')
+const chalk = require('chalk')
+const webpack = require('webpack')
+const config = require('../config')
+const webpackConfig = require('./webpack.prod.conf')
 
-var spinner = ora('building for production...')
+const spinner = ora('building for production...')
 spinner.start()
 
-var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
-rm('-rf', assetsPath)
-mkdir('-p', assetsPath)
-cp('-R', 'static/*', assetsPath)
-
-webpack(webpackConfig, function (err, stats) {
-  spinner.stop()
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
   if (err) throw err
-  process.stdout.write(stats.toString({
-    colors: true,
-    modules: false,
-    children: false,
-    chunks: false,
-    chunkModules: false
-  }) + '\n')
+  webpack(webpackConfig, function (err, stats) {
+    spinner.stop()
+    if (err) throw err
+    process.stdout.write(stats.toString({
+      colors: true,
+      modules: false,
+      children: false,
+      chunks: false,
+      chunkModules: false
+    }) + '\n\n')
+
+    if (stats.hasErrors()) {
+      console.log(chalk.red('  Build failed with errors.\n'))
+      process.exit(1)
+    }
+
+    console.log(chalk.cyan('  Build complete.\n'))
+    console.log(chalk.yellow(
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
+      '  Opening index.html over file:// won\'t work.\n'
+    ))
+  })
 })

+ 20 - 16
build/check-versions.js

@@ -1,28 +1,32 @@
-var semver = require('semver')
-var chalk = require('chalk')
-var packageConfig = require('../package.json')
-var exec = function (cmd) {
-  return require('child_process')
-    .execSync(cmd).toString().trim()
+'use strict'
+const chalk = require('chalk')
+const semver = require('semver')
+const packageConfig = require('../package.json')
+const shell = require('shelljs')
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
 }
 
-var versionRequirements = [
+const versionRequirements = [
   {
     name: 'node',
     currentVersion: semver.clean(process.version),
     versionRequirement: packageConfig.engines.node
-  },
-  {
+  }
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
     name: 'npm',
     currentVersion: exec('npm --version'),
     versionRequirement: packageConfig.engines.npm
-  }
-]
+  })
+}
 
 module.exports = function () {
-  var warnings = []
-  for (var i = 0; i < versionRequirements.length; i++) {
-    var mod = versionRequirements[i]
+  const warnings = []
+  for (let i = 0; i < versionRequirements.length; i++) {
+    const mod = versionRequirements[i]
     if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
       warnings.push(mod.name + ': ' +
         chalk.red(mod.currentVersion) + ' should be ' +
@@ -35,8 +39,8 @@ module.exports = function () {
     console.log('')
     console.log(chalk.yellow('To use this template, you must update following to modules:'))
     console.log()
-    for (var i = 0; i < warnings.length; i++) {
-      var warning = warnings[i]
+    for (let i = 0; i < warnings.length; i++) {
+      const warning = warnings[i]
       console.log('  ' + warning)
     }
     console.log()

+ 6 - 55
build/dev-server.js

@@ -1,18 +1,11 @@
 require('./check-versions')()
 var config = require('../config')
-if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
 var path = require('path')
 var express = require('express')
-var webpack = require('webpack')
 var opn = require('opn')
-var proxyMiddleware = require('http-proxy-middleware')
-var webpackConfig = require('./webpack.dev.conf')
 
 // default port where dev server listens for incoming traffic
-var port = process.env.PORT || config.dev.port
-// Define HTTP proxies to your custom API backend
-// https://github.com/chimurai/http-proxy-middleware
-var proxyTable = config.dev.proxyTable
+var port = '8088'
 
 var app = express()
 
@@ -46,62 +39,20 @@ apiRoutes.get('/ratings', function (req, res) {
 
 app.use('/api', apiRoutes)
 
-var compiler = webpack(webpackConfig)
-
-var devMiddleware = require('webpack-dev-middleware')(compiler, {
-  publicPath: webpackConfig.output.publicPath,
-  quiet: true
-})
-
-var hotMiddleware = require('webpack-hot-middleware')(compiler, {
-  log: () => {
-  }
-})
-// 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
-var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
-app.use(staticPath, express.static('./static'))
-
-var uri = 'http://localhost:' + port
-
-devMiddleware.waitUntilValid(function () {
-  console.log('> Listening at ' + uri + '\n')
-})
+var uri = 'http://0.0.0.0:' + port
 
 module.exports = app.listen(port, function (err) {
+  console.log('> Listening at ' + uri + '\n')
   if (err) {
     console.log(err)
     return
   }
 
   // when env is testing, don't need open it
-  if (process.env.NODE_ENV !== 'testing') {
-    opn(uri)
-  }
+  // if (process.env.NODE_ENV !== 'testing') {
+  //   opn(uri)
+  // }
 })

BIN
build/logo.png


+ 68 - 31
build/utils.js

@@ -1,9 +1,11 @@
-var path = require('path')
-var config = require('../config')
-var ExtractTextPlugin = require('extract-text-webpack-plugin')
+'use strict'
+const path = require('path')
+const config = require('../config')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const pkg = require('../package.json')
 
 exports.assetsPath = function (_path) {
-  var assetsSubDirectory = process.env.NODE_ENV === 'production'
+  const assetsSubDirectory = process.env.NODE_ENV === 'production'
     ? config.build.assetsSubDirectory
     : config.dev.assetsSubDirectory
   return path.posix.join(assetsSubDirectory, _path)
@@ -11,51 +13,86 @@ exports.assetsPath = function (_path) {
 
 exports.cssLoaders = function (options) {
   options = options || {}
+
+  const cssLoader = {
+    loader: 'css-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  var postcssLoader = {
+    loader: 'postcss-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
   // 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('!')
+  function generateLoaders (loader, loaderOptions) {
+    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
+    if (loader) {
+      loaders.push({
+        loader: loader + '-loader',
+        options: Object.assign({}, loaderOptions, {
+          sourceMap: options.sourceMap
+        })
+      })
+    }
 
     // Extract CSS when that option is specified
     // (which is the case during production build)
     if (options.extract) {
-      return ExtractTextPlugin.extract('vue-style-loader', sourceLoader)
+      return ExtractTextPlugin.extract({
+        use: loaders,
+        fallback: 'vue-style-loader'
+      })
     } else {
-      return ['vue-style-loader', sourceLoader].join('!')
+      return ['vue-style-loader'].concat(loaders)
     }
   }
 
-  // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
   return {
-    css: generateLoaders(['css']),
-    postcss: generateLoaders(['css']),
-    less: generateLoaders(['css', 'less']),
-    sass: generateLoaders(['css', 'sass?indentedSyntax']),
-    scss: generateLoaders(['css', 'sass']),
-    stylus: generateLoaders(['css', 'stylus']),
-    styl: generateLoaders(['css', 'stylus'])
+    css: generateLoaders(),
+    postcss: generateLoaders(),
+    less: generateLoaders('less'),
+    sass: generateLoaders('sass', { indentedSyntax: true }),
+    scss: generateLoaders('sass'),
+    stylus: generateLoaders('stylus'),
+    styl: generateLoaders('stylus')
   }
 }
 
 // Generate loaders for standalone style files (outside of .vue)
 exports.styleLoaders = function (options) {
-  var output = []
-  var loaders = exports.cssLoaders(options)
-  for (var extension in loaders) {
-    var loader = loaders[extension]
+  const output = []
+  const loaders = exports.cssLoaders(options)
+  for (const extension in loaders) {
+    const loader = loaders[extension]
     output.push({
       test: new RegExp('\\.' + extension + '$'),
-      loader: loader
+      use: loader
     })
   }
   return output
 }
+
+exports.createNotifierCallback = function () {
+  const notifier = require('node-notifier')
+
+  return (severity, errors) => {
+    if (severity !== 'error') {
+      return
+    }
+    const error = errors[0]
+
+    const filename = error.file.split('!').pop()
+    notifier.notify({
+      title: pkg.name,
+      message: severity + ': ' + error.name,
+      subtitle: filename || '',
+      icon: path.join(__dirname, 'logo.png')
+    })
+  }
+}

+ 22 - 0
build/vue-loader.conf.js

@@ -0,0 +1,22 @@
+'use strict'
+const utils = require('./utils')
+const config = require('../config')
+const isProduction = process.env.NODE_ENV === 'production'
+const sourceMapEnabled = isProduction
+  ? config.build.productionSourceMap
+  : config.dev.cssSourceMap
+
+
+module.exports = {
+  loaders: utils.cssLoaders({
+    sourceMap: sourceMapEnabled,
+    extract: isProduction
+  }),
+  cssSourceMap: sourceMapEnabled,
+  transformToRequire: {
+    video: 'src',
+    source: 'src',
+    img: 'src',
+    image: 'xlink:href'
+  }
+}

+ 41 - 61
build/webpack.base.conf.js

@@ -1,99 +1,79 @@
-var path = require('path')
-var config = require('../config')
-var utils = require('./utils')
-var projectRoot = path.resolve(__dirname, '../')
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const config = require('../config')
+const vueLoaderConfig = require('./vue-loader.conf')
 
-var env = process.env.NODE_ENV
-// check env & config/index.js to decide whether to enable CSS source maps for the
-// various preprocessor loaders added to vue-loader at the end of this file
-var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
-var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
-var useCssSourceMap = cssSourceMapDev || cssSourceMapProd
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
 
 module.exports = {
+  context: path.resolve(__dirname, '../'),
   entry: {
     app: './src/main.js'
   },
   output: {
     path: config.build.assetsRoot,
-    publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
-    filename: '[name].js'
+    filename: '[name].js',
+    publicPath: process.env.NODE_ENV === 'production'
+      ? config.build.assetsPublicPath
+      : config.dev.assetsPublicPath
   },
   resolve: {
-    extensions: ['', '.js', '.vue', '.json'],
-    fallback: [path.join(__dirname, '../node_modules')],
+    extensions: ['.js', '.vue', '.json'],
     alias: {
       'src': path.resolve(__dirname, '../src'),
       'common': path.resolve(__dirname, '../src/common'),
       'components': path.resolve(__dirname, '../src/components')
     }
   },
-  resolveLoader: {
-    fallback: [path.join(__dirname, '../node_modules')]
-  },
   module: {
-    preLoaders: [
-      {
-        test: /\.vue$/,
-        loader: 'eslint',
-        include: [
-          path.join(projectRoot, 'src')
-        ],
-        exclude: /node_modules/
-      },
-      {
-        test: /\.js$/,
-        loader: 'eslint',
-        include: [
-          path.join(projectRoot, 'src')
-        ],
-        exclude: /node_modules/
-      }
-    ],
-    loaders: [
+    rules: [
+      ...(config.dev.useEslint? [{
+        test: /\.(js|vue)$/,
+        loader: 'eslint-loader',
+        enforce: 'pre',
+        include: [resolve('src'), resolve('test')],
+        options: {
+          formatter: require('eslint-friendly-formatter'),
+          emitWarning: !config.dev.showEslintErrorsInOverlay
+        }
+      }] : []),
       {
         test: /\.vue$/,
-        loader: 'vue'
+        loader: 'vue-loader',
+        options: vueLoaderConfig
       },
       {
         test: /\.js$/,
-        loader: 'babel',
-        include: [
-          path.join(projectRoot, 'src')
-        ],
-        exclude: /node_modules/
-      },
-      {
-        test: /\.json$/,
-        loader: 'json'
+        loader: 'babel-loader',
+        include: [resolve('src'), resolve('test')]
       },
       {
         test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
-        loader: 'url',
-        query: {
+        loader: 'url-loader',
+        options: {
           limit: 10000,
           name: utils.assetsPath('img/[name].[hash:7].[ext]')
         }
       },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
       {
         test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
-        loader: 'url',
-        query: {
+        loader: 'url-loader',
+        options: {
           limit: 10000,
           name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
         }
       }
     ]
-  },
-  eslint: {
-    formatter: require('eslint-friendly-formatter')
-  },
-  vue: {
-    loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }),
-    postcss: [
-      require('autoprefixer')({
-        browsers: ['last 2 versions', 'Android >= 4.0']
-      })
-    ]
   }
 }

+ 63 - 22
build/webpack.dev.conf.js

@@ -1,36 +1,77 @@
-var config = require('../config')
-var webpack = require('webpack')
-var merge = require('webpack-merge')
-var utils = require('./utils')
-var baseWebpackConfig = require('./webpack.base.conf')
-var HtmlWebpackPlugin = require('html-webpack-plugin')
-var FriendlyErrors = require('friendly-errors-webpack-plugin')
+'use strict'
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+const portfinder = require('portfinder')
 
-// add hot-reload related code to entry chunks
-Object.keys(baseWebpackConfig.entry).forEach(function (name) {
-  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
-})
-
-module.exports = merge(baseWebpackConfig, {
+const devWebpackConfig = merge(baseWebpackConfig, {
   module: {
-    loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: config.dev.devtool,
+  
+  // these devServer options should be customized in /config/index.js
+  devServer: {
+    clientLogLevel: 'warning',
+    historyApiFallback: true,
+    hot: true,
+    host: process.env.HOST || config.dev.host,
+    port: process.env.PORT || config.dev.port,
+    open: config.dev.autoOpenBrowser,
+    overlay: config.dev.errorOverlay ? {
+      warnings: false,
+      errors: true,
+    } : false,
+    publicPath: config.dev.assetsPublicPath,
+    proxy: config.dev.proxyTable,
+    quiet: true, // necessary for FriendlyErrorsPlugin
+    watchOptions: {
+      poll: config.dev.poll,
+    }
   },
-  // eval-source-map is faster for development
-  devtool: '#eval-source-map',
   plugins: [
     new webpack.DefinePlugin({
-      'process.env': config.dev.env
-    }),
-    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
-    new webpack.optimize.OccurrenceOrderPlugin(),
+      'process.env': require('../config/dev.env')
+    }), 
     new webpack.HotModuleReplacementPlugin(),
-    new webpack.NoErrorsPlugin(),
+    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
+    new webpack.NoEmitOnErrorsPlugin(),
     // https://github.com/ampedandwired/html-webpack-plugin
     new HtmlWebpackPlugin({
       filename: 'index.html',
       template: 'index.html',
       inject: true
     }),
-    new FriendlyErrors()
   ]
 })
+
+module.exports = new Promise((resolve, reject) => {
+  portfinder.basePort = process.env.PORT || config.dev.port
+  portfinder.getPort((err, port) => {
+    if (err) {
+      reject(err)
+    } else {
+      // publish the new Port, necessary for e2e tests
+      process.env.PORT = port
+      // add port to devServer config
+      devWebpackConfig.devServer.port = port
+
+      // Add FriendlyErrorsPlugin
+      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
+        compilationSuccessInfo: {
+          messages: [`Your application is running here: http://${config.dev.host}:${port}`],
+        },
+        onErrors: config.dev.notifyOnErrors
+        ? utils.createNotifierCallback()
+        : undefined
+      }))
+
+      resolve(devWebpackConfig)
+    }
+  })
+})

+ 70 - 26
build/webpack.prod.conf.js

@@ -1,42 +1,59 @@
-var path = require('path')
-var config = require('../config')
-var utils = require('./utils')
-var webpack = require('webpack')
-var merge = require('webpack-merge')
-var baseWebpackConfig = require('./webpack.base.conf')
-var ExtractTextPlugin = require('extract-text-webpack-plugin')
-var HtmlWebpackPlugin = require('html-webpack-plugin')
-var env = config.build.env
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
 
-var webpackConfig = merge(baseWebpackConfig, {
+const env = require('../config/prod.env')
+
+const webpackConfig = merge(baseWebpackConfig, {
   module: {
-    loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true })
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true,
+      usePostCSS: true
+    })
   },
-  devtool: config.build.productionSourceMap ? '#source-map' : false,
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
   output: {
     path: config.build.assetsRoot,
     filename: utils.assetsPath('js/[name].[chunkhash].js'),
-    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
-  },
-  vue: {
-    loaders: utils.cssLoaders({
-      sourceMap: config.build.productionSourceMap,
-      extract: true
-    })
+    chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')
   },
   plugins: [
     // http://vuejs.github.io/vue-loader/en/workflow/production.html
     new webpack.DefinePlugin({
       'process.env': env
     }),
+    // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
     new webpack.optimize.UglifyJsPlugin({
       compress: {
         warnings: false
-      }
+      },
+      sourceMap: config.build.productionSourceMap,
+      parallel: true
     }),
-    new webpack.optimize.OccurrenceOrderPlugin(),
     // extract css into its own file
-    new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
+    new ExtractTextPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css'),
+      // set the following option to `true` if you want to extract CSS from
+      // codesplit chunks into this main css file as well.
+      // This will result in *all* of your app's CSS being loaded upfront.
+      allChunks: false,
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: config.build.productionSourceMap
+      ? { safe: true, map: { inline: false } }
+      : { safe: true }
+    }),
     // 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
@@ -54,10 +71,14 @@ var webpackConfig = merge(baseWebpackConfig, {
       // necessary to consistently work with multiple chunks via CommonsChunkPlugin
       chunksSortMode: 'dependency'
     }),
+    // keep module.id stable when vender modules does not change
+    new webpack.HashedModuleIdsPlugin(),
+    // enable scope hoisting
+    new webpack.optimize.ModuleConcatenationPlugin(),
     // split vendor js into its own file
     new webpack.optimize.CommonsChunkPlugin({
       name: 'vendor',
-      minChunks: function (module, count) {
+      minChunks: function (module) {
         // any required modules inside node_modules are extracted to vendor
         return (
           module.resource &&
@@ -72,13 +93,31 @@ var webpackConfig = merge(baseWebpackConfig, {
     // prevent vendor hash from being updated whenever app bundle is updated
     new webpack.optimize.CommonsChunkPlugin({
       name: 'manifest',
-      chunks: ['vendor']
-    })
+      minChunks: Infinity
+    }),
+    // This instance extracts shared chunks from code splitted chunks and bundles them
+    // in a separate chunk, similar to the vendor chunk
+    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'app',
+      async: 'vendor-async',
+      children: true,
+      minChunks: 3
+    }),
+
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
   ]
 })
 
 if (config.build.productionGzip) {
-  var CompressionWebpackPlugin = require('compression-webpack-plugin')
+  const CompressionWebpackPlugin = require('compression-webpack-plugin')
 
   webpackConfig.plugins.push(
     new CompressionWebpackPlugin({
@@ -95,4 +134,9 @@ if (config.build.productionGzip) {
   )
 }
 
+if (config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
 module.exports = webpackConfig

+ 32 - 0
build/webpack.test.conf.js

@@ -0,0 +1,32 @@
+'use strict'
+// This is the webpack config used for unit tests.
+
+const utils = require('./utils')
+const webpack = require('webpack')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+
+const webpackConfig = merge(baseWebpackConfig, {
+  // use inline sourcemap for karma-sourcemap-loader
+  module: {
+    rules: utils.styleLoaders()
+  },
+  devtool: '#inline-source-map',
+  resolveLoader: {
+    alias: {
+      // necessary to to make lang="scss" work in test when using vue-loader's ?inject option
+      // see discussion at https://github.com/vuejs/vue-loader/issues/724
+      'scss-loader': 'sass-loader'
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': require('../config/test.env')
+    })
+  ]
+})
+
+// no need for app entry during tests
+delete webpackConfig.entry
+
+module.exports = webpackConfig

+ 3 - 2
config/dev.env.js

@@ -1,5 +1,6 @@
-var merge = require('webpack-merge')
-var prodEnv = require('./prod.env')
+'use strict'
+const merge = require('webpack-merge')
+const prodEnv = require('./prod.env')
 
 module.exports = merge(prodEnv, {
   NODE_ENV: '"development"'

+ 78 - 29
config/index.js

@@ -1,33 +1,82 @@
+'use strict'
+// Template version: 1.2.3
 // see http://vuejs-templates.github.io/webpack for documentation.
-var path = require('path')
+
+const path = require('path')
 
 module.exports = {
-	build: {
-		env: require('./prod.env'),
-		index: path.resolve(__dirname, '../dist/index.html'),
-		assetsRoot: path.resolve(__dirname, '../dist'),
-		assetsSubDirectory: 'static',
-		assetsPublicPath: '',
-		productionSourceMap: false,
-		// Gzip off by default as many popular static hosts such as
-		// Surge or Netlify already gzip all static assets for you.
-		// Before setting to `true`, make sure to:
-		// npm install --save-dev compression-webpack-plugin
-		productionGzip: false,
-		productionGzipExtensions: ['js', 'css'],
-		port: 8900
-	},
-	dev: {
-		env: require('./dev.env'),
-		port: 8088,
-		assetsSubDirectory: 'static',
-		assetsPublicPath: '/',
-		proxyTable: {},
-		// CSS Sourcemaps off by default because relative paths are "buggy"
-		// with this option, according to the CSS-Loader README
-		// (https://github.com/webpack/css-loader#sourcemaps)
-		// In our experience, they generally work as expected,
-		// just be aware of this issue when enabling this option.
-		cssSourceMap: false
-	}
+  dev: {
+
+    // Paths
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {
+        '/api': 'http://localhost:8088'
+    },
+    // Various Dev Server settings
+    host: '0.0.0.0', // can be overwritten by process.env.HOST
+    port: 8080, // can be overwritten by process.env.HOST, if port is in use, a free one will be determined
+    autoOpenBrowser: false,
+    errorOverlay: true,
+    notifyOnErrors: true,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: 'eval-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    // CSS Sourcemaps off by default because relative paths are "buggy"
+    // with this option, according to the CSS-Loader README
+    // (https://github.com/webpack/css-loader#sourcemaps)
+    // In our experience, they generally work as expected,
+    // just be aware of this issue when enabling this option.
+    cssSourceMap: false,
+  },
+  
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: true,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+    
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+    
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
 }

+ 1 - 0
config/prod.env.js

@@ -1,3 +1,4 @@
+'use strict'
 module.exports = {
   NODE_ENV: '"production"'
 }

+ 58 - 55
package.json

@@ -1,72 +1,75 @@
 {
-  "name": "sell",
+  "name": "vue-sell",
   "version": "1.0.0",
-  "description": "sell app",
-  "author": "ustbhuangyi <280309453@qq.com>",
+  "description": "A Vue.js project",
+  "author": "Junx <junxjobs@gmail.com>",
   "private": true,
   "scripts": {
-    "dev": "node build/dev-server.js",
-    "build": "node build/build.js",
-    "test": "",
-    "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "server": "node build/dev-server.js",
+    "start": "npm run dev",
+    "lint": "eslint --ext .js,.vue src",
+    "build": "node build/build.js"
   },
-  "keywords": [
-    "vue",
-    "vue-sell",
-    "webapp"
-  ],
   "dependencies": {
-    "vue": "^2.2.1",
-    "vue-resource": "1.0.3",
-    "vue-router": "^2.2.0",
-    "babel-runtime": "^6.0.0",
-    "better-scroll": "^1.4.2"
+    "better-scroll": "^1.4.2",
+    "vue": "^2.5.2",
+    "vue-resource": "^1.3.4",
+    "vue-router": "^3.0.1"
   },
   "devDependencies": {
-    "autoprefixer": "^6.4.0",
-    "babel-core": "^6.0.0",
-    "babel-eslint": "^7.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",
-    "babel-register": "^6.0.0",
-    "chalk": "^1.1.3",
-    "connect-history-api-fallback": "^1.1.0",
-    "css-loader": "^0.25.0",
-    "eslint": "^3.7.1",
-    "eslint-friendly-formatter": "^2.0.5",
-    "eslint-loader": "^1.5.0",
-    "eslint-plugin-html": "^1.3.0",
-    "eslint-config-standard": "^6.1.0",
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.22.1",
+    "babel-eslint": "^7.1.1",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-stage-2": "^6.22.0",
+    "babel-register": "^6.22.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.28.0",
+    "eslint": "^3.19.0",
+    "eslint-config-standard": "^10.2.1",
+    "eslint-friendly-formatter": "^3.0.0",
+    "eslint-loader": "^1.7.1",
+    "eslint-plugin-html": "^3.0.0",
+    "eslint-plugin-import": "^2.7.0",
+    "eslint-plugin-node": "^5.2.0",
     "eslint-plugin-promise": "^3.4.0",
-    "eslint-plugin-standard": "^2.0.1",
+    "eslint-plugin-standard": "^3.0.1",
     "eventsource-polyfill": "^0.9.6",
-    "express": "^4.13.3",
-    "extract-text-webpack-plugin": "^1.0.1",
-    "file-loader": "^0.9.0",
-    "friendly-errors-webpack-plugin": "^1.1.2",
-    "function-bind": "^1.0.2",
-    "html-webpack-plugin": "^2.8.1",
-    "http-proxy-middleware": "^0.17.2",
-    "json-loader": "^0.5.4",
+    "extract-text-webpack-plugin": "^3.0.0",
+    "file-loader": "^1.1.4",
+    "friendly-errors-webpack-plugin": "^1.6.1",
+    "html-webpack-plugin": "^2.30.1",
+    "node-notifier": "^5.1.2",
+    "optimize-css-assets-webpack-plugin": "^3.2.0",
+    "ora": "^1.2.0",
+    "portfinder": "^1.0.13",
+    "postcss-import": "^11.0.0",
+    "postcss-loader": "^2.0.8",
+    "rimraf": "^2.6.0",
     "semver": "^5.3.0",
-    "opn": "^4.0.2",
-    "ora": "^0.3.0",
-    "shelljs": "^0.7.4",
-    "url-loader": "^0.5.7",
-    "vue-loader": "^11.1.4",
-    "vue-style-loader": "^2.0.0",
+    "shelljs": "^0.7.6",
     "stylus": "^0.54.5",
-    "stylus-loader": "^2.1.1",
-    "vue-template-compiler": "^2.2.1",
-    "webpack": "^1.13.2",
-    "webpack-dev-middleware": "^1.8.3",
-    "webpack-hot-middleware": "^2.12.2",
-    "webpack-merge": "^0.14.1"
+    "stylus-loader": "^3.0.1",
+    "url-loader": "^0.5.8",
+    "vue-loader": "^13.3.0",
+    "vue-style-loader": "^3.0.1",
+    "vue-template-compiler": "^2.5.2",
+    "webpack": "^3.6.0",
+    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-dev-server": "^2.9.1",
+    "webpack-merge": "^4.1.0"
   },
   "engines": {
     "node": ">= 4.0.0",
     "npm": ">= 3.0.0"
-  }
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
 }

+ 1 - 1
src/App.vue

@@ -60,8 +60,8 @@
     width: 100%
     height: 40px
     line-height: 40px
-  // border-bottom: 1px solid rgba(7, 17, 27, 0.1)
     border-1px(rgba(7, 17, 27, 0.1))
+  //border-bottom: 1px solid rgba(7, 17, 27, 0.1)
     .tab-item
       flex: 1
       text-align: center

+ 1 - 24
src/main.js

@@ -1,35 +1,12 @@
 import Vue from 'vue';
-import VueRouter from 'vue-router';
 import VueResource from 'vue-resource';
 import App from './App';
-import goods from 'components/goods/goods';
-import ratings from 'components/ratings/ratings';
-import seller from 'components/seller/seller';
+import router from './router/index.js';
 
 import 'common/stylus/index.styl';
 
-Vue.use(VueRouter);
 Vue.use(VueResource);
 
-const routes = [{
-  path: '/',
-  redirect: '/goods'
-}, {
-  path: '/goods',
-  component: goods
-}, {
-  path: '/ratings',
-  component: ratings
-}, {
-  path: '/seller',
-  component: seller
-}];
-
-const router = new VueRouter({
-  linkActiveClass: 'active',
-  routes
-});
-
 /* eslint-disable no-new */
 new Vue({
   el: '#app',

+ 26 - 0
src/router/index.js

@@ -0,0 +1,26 @@
+import Vue from 'vue';
+import Router from 'vue-router';
+import goods from 'components/goods/goods';
+import ratings from 'components/ratings/ratings';
+import seller from 'components/seller/seller';
+
+Vue.use(Router);
+
+const routes = [{
+  path: '/',
+  redirect: '/goods'
+}, {
+  path: '/goods',
+  component: goods
+}, {
+  path: '/ratings',
+  component: ratings
+}, {
+  path: '/seller',
+  component: seller
+}];
+
+export default new Router({
+    linkActiveClass: 'active',
+    routes
+});