├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── README.md
├── build
├── build.js
├── dev-client.js
├── dev-server.js
├── utils.js
├── webpack.base.conf.js
├── webpack.dev.conf.js
└── webpack.prod.conf.js
├── config
├── dev.env.js
├── index.js
├── prod.env.js
└── test.env.js
├── dist
├── static
│ ├── api
│ │ ├── .gitkeep
│ │ ├── center
│ │ │ ├── getCenter.json
│ │ │ ├── getFavourite.json
│ │ │ ├── getNotification.json
│ │ │ └── images
│ │ │ │ ├── collect1.jpg
│ │ │ │ ├── collect2.jpg
│ │ │ │ ├── collect3.jpg
│ │ │ │ └── collect4.jpg
│ │ ├── destination
│ │ │ ├── getDestination.json
│ │ │ └── images
│ │ │ │ ├── d_1.jpg
│ │ │ │ ├── d_2.jpg
│ │ │ │ ├── d_3.jpg
│ │ │ │ └── d_4.jpg
│ │ ├── home
│ │ │ ├── homepageV3.json
│ │ │ └── images
│ │ │ │ ├── a1.jpg
│ │ │ │ ├── a2.jpg
│ │ │ │ ├── a3.jpg
│ │ │ │ ├── banner1.jpg
│ │ │ │ ├── banner2.jpg
│ │ │ │ ├── l1.jpg
│ │ │ │ ├── l2.jpg
│ │ │ │ ├── l3.jpg
│ │ │ │ ├── mu1.jpg
│ │ │ │ ├── mu2.jpg
│ │ │ │ ├── mu3.jpg
│ │ │ │ ├── mu4.jpg
│ │ │ │ ├── mu5.jpg
│ │ │ │ ├── mu6.jpg
│ │ │ │ ├── r1.jpg
│ │ │ │ ├── r2.jpg
│ │ │ │ ├── remai1.jpg
│ │ │ │ ├── remai2.jpg
│ │ │ │ └── remai3.jpg
│ │ ├── order
│ │ │ ├── countShopCartNum.json
│ │ │ ├── deleteShopCart.json
│ │ │ └── shopCart.json
│ │ └── user
│ │ │ └── login.json
│ ├── css
│ │ ├── center.648e76953f5e55ed22da2a4105a9fde8.css
│ │ ├── destinationIndex.a06f9f4562800ea7a1521640fb01b7ce.css
│ │ ├── index.3d5cd0837bdb92d6cd84fd45307504fc.css
│ │ ├── login.c2d494d0e20f62bb52603ed6b4466099.css
│ │ └── shoppingCart.88d4f1ac6dd10f7ebebf1d6640bb3be9.css
│ ├── images
│ │ ├── logined.536d85d.jpg
│ │ ├── qq_login.59cc5b5.png
│ │ ├── sina_login.3e2c8da.png
│ │ └── wechat_login.617486b.png
│ └── js
│ │ ├── 0.1489d44a271ef2eedeed.js
│ │ ├── 1.1fa23c38d9aed86b1147.js
│ │ ├── 2.19f3b5257d948643990d.js
│ │ ├── 3.94ceb073a05646b5ad62.js
│ │ ├── 4.d7c4439221431031cbe7.js
│ │ ├── 5.49cea5f6f4fb98e959e3.js
│ │ ├── center.44c7b859c2e838fb3da9.js
│ │ ├── destinationIndex.35369b96573b7ec198d7.js
│ │ ├── flexible.63f20e39e6dee4aa5948.js
│ │ ├── index.cd01b2f45b8c09baa884.js
│ │ ├── lib
│ │ ├── base64.js
│ │ └── flexible
│ │ │ └── flexible.js
│ │ ├── login.776892e061fdf7322881.js
│ │ ├── manifest.4dfd36d9c5897eed2fe9.js
│ │ ├── shoppingCart.f71f016296dbfb71a8f5.js
│ │ └── vendor.23c55bb9879e852e44ed.js
└── views
│ ├── center.html
│ ├── destinationIndex.html
│ ├── index.html
│ ├── login.html
│ └── shoppingCart.html
├── note
├── R10_关于商品SKU选择问题.md
├── R1_base64插件expose或imports报错问题.md
├── R2_modules之间的action以及mutation如何相互调用.md
├── R3_根据某个key获取数组json对应的index.md
├── R4_selectall.md
├── R5_试点增加多语言的支持.md
├── R6_使用mock模拟后端接口返回.md
├── R7_对多页面功能组织划分的一些思考.md
├── R8_组件style样式npm_run_build样式生成不出来问题.md
├── R9_登录拦截.md
├── byluchanan.docx
├── vue生命周期来解释为什么vue-awesome-swiper插件中length=0.docx
└── 消息列表使用vuex来获取数据工作流程.docx
├── package-lock.json
├── package.json
├── src
├── assets
│ ├── css
│ │ └── .gitkeep
│ ├── fonts
│ │ ├── .gitkeep
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ └── iconfont.woff
│ ├── images
│ │ └── icon
│ │ │ ├── arrow_right.png
│ │ │ ├── cart.png
│ │ │ ├── checkbox.png
│ │ │ ├── checkbox_on.png
│ │ │ ├── destination.png
│ │ │ ├── destination_on.png
│ │ │ ├── dot.png
│ │ │ ├── dot_on.png
│ │ │ ├── header_right_edit.png
│ │ │ ├── home.png
│ │ │ ├── home_on.png
│ │ │ ├── lazy_load_fail.png
│ │ │ ├── lazy_load_loading.png
│ │ │ ├── loading.gif
│ │ │ ├── my.png
│ │ │ ├── my_on.png
│ │ │ ├── search.png
│ │ │ └── service.png
│ ├── js
│ │ ├── base.js
│ │ ├── common.js
│ │ ├── config.js
│ │ ├── filters.js
│ │ ├── lib
│ │ │ └── calendar
│ │ │ │ ├── calendar.js
│ │ │ │ └── calendar.scss
│ │ ├── mock
│ │ │ ├── center
│ │ │ │ ├── index.js
│ │ │ │ └── waitForCommentList.js
│ │ │ ├── index.js
│ │ │ └── shopping.js
│ │ └── tools.js
│ ├── locales
│ │ ├── en-US.json
│ │ └── zh-CN.json
│ ├── logo.png
│ └── scss
│ │ ├── base
│ │ ├── _common.scss
│ │ ├── _cssreset.scss
│ │ ├── _extend.scss
│ │ ├── _footer.scss
│ │ ├── _function.scss
│ │ ├── _header.scss
│ │ ├── _mixin.scss
│ │ ├── _necessary.scss
│ │ └── _variable.scss
│ │ └── common.scss
├── components
│ ├── common
│ │ ├── footer.vue
│ │ ├── list-bottom.vue
│ │ ├── search-icon.vue
│ │ └── service-icon.vue
│ ├── home
│ │ ├── home-banner.vue
│ │ ├── home-header.vue
│ │ └── home-topic.vue
│ └── my
│ │ ├── images
│ │ ├── back.png
│ │ ├── message.png
│ │ ├── search.png
│ │ └── setting.png
│ │ └── my-header.vue
├── views
│ ├── center
│ │ ├── App.vue
│ │ ├── app.js
│ │ ├── index.html
│ │ ├── pages
│ │ │ ├── becomment
│ │ │ │ └── index.vue
│ │ │ ├── collect
│ │ │ │ └── index.vue
│ │ │ ├── message
│ │ │ │ └── index.vue
│ │ │ ├── my
│ │ │ │ ├── images
│ │ │ │ │ ├── all.png
│ │ │ │ │ ├── collect.png
│ │ │ │ │ ├── comment.png
│ │ │ │ │ ├── hotel.png
│ │ │ │ │ ├── logined.jpg
│ │ │ │ │ ├── nologin.jpg
│ │ │ │ │ ├── paying.png
│ │ │ │ │ ├── service.png
│ │ │ │ │ ├── taobao.png
│ │ │ │ │ └── traveller.png
│ │ │ │ ├── index.vue
│ │ │ │ └── scss
│ │ │ │ │ └── my.scss
│ │ │ ├── service
│ │ │ │ ├── images
│ │ │ │ │ └── tel.png
│ │ │ │ └── index.vue
│ │ │ └── setting
│ │ │ │ └── index.vue
│ │ └── scss
│ │ │ ├── center.scss
│ │ │ └── collect.scss
│ ├── destinationIndex
│ │ ├── destinationIndex.html
│ │ ├── destinationIndex.js
│ │ ├── destinationIndex.vue
│ │ └── scss
│ │ │ └── destinationIndex.scss
│ ├── index
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── index.vue
│ │ └── scss
│ │ │ └── home.scss
│ ├── login
│ │ ├── images
│ │ │ ├── hr_login.png
│ │ │ ├── qq_login.png
│ │ │ ├── sina_login.png
│ │ │ └── wechat_login.png
│ │ ├── login.html
│ │ ├── login.js
│ │ ├── login.vue
│ │ └── scss
│ │ │ └── login.scss
│ └── shoppingCart
│ │ ├── shoppingCart.html
│ │ ├── shoppingCart.js
│ │ └── shoppingCart.vue
└── vuex
│ ├── api.js
│ ├── modules
│ ├── center
│ │ └── becomment.js
│ ├── collect.js
│ ├── common.js
│ ├── destinationIndex.js
│ ├── index.js
│ ├── login.js
│ ├── messageList.js
│ ├── my.js
│ └── shoppingCart.js
│ ├── mutation-types.js
│ └── store.js
├── static
├── .gitkeep
├── api
│ ├── .gitkeep
│ ├── center
│ │ ├── getCenter.json
│ │ ├── getFavourite.json
│ │ ├── getNotification.json
│ │ └── images
│ │ │ ├── collect1.jpg
│ │ │ ├── collect2.jpg
│ │ │ ├── collect3.jpg
│ │ │ └── collect4.jpg
│ ├── destination
│ │ ├── getDestination.json
│ │ └── images
│ │ │ ├── d_1.jpg
│ │ │ ├── d_2.jpg
│ │ │ ├── d_3.jpg
│ │ │ └── d_4.jpg
│ ├── home
│ │ ├── homepageV3.json
│ │ └── images
│ │ │ ├── a1.jpg
│ │ │ ├── a2.jpg
│ │ │ ├── a3.jpg
│ │ │ ├── banner1.jpg
│ │ │ ├── banner2.jpg
│ │ │ ├── l1.jpg
│ │ │ ├── l2.jpg
│ │ │ ├── l3.jpg
│ │ │ ├── mu1.jpg
│ │ │ ├── mu2.jpg
│ │ │ ├── mu3.jpg
│ │ │ ├── mu4.jpg
│ │ │ ├── mu5.jpg
│ │ │ ├── mu6.jpg
│ │ │ ├── r1.jpg
│ │ │ ├── r2.jpg
│ │ │ ├── remai1.jpg
│ │ │ ├── remai2.jpg
│ │ │ └── remai3.jpg
│ ├── order
│ │ ├── countShopCartNum.json
│ │ ├── deleteShopCart.json
│ │ └── shopCart.json
│ └── user
│ │ └── login.json
└── js
│ └── lib
│ ├── base64.js
│ └── flexible
│ └── flexible.js
├── test
├── e2e
│ ├── custom-assertions
│ │ └── elementCount.js
│ ├── nightwatch.conf.js
│ ├── runner.js
│ └── specs
│ │ └── test.js
└── unit
│ ├── .eslintrc
│ ├── index.js
│ ├── karma.conf.js
│ └── specs
│ └── Hello.spec.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2"],
3 | "plugins": ["transform-runtime"],
4 | "comments": false
5 | }
6 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | config/*.js
3 | src/assets/js/lib/**/*.js
4 | static/js/lib/**/*.js
5 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: 'babel-eslint',
4 | parserOptions: {
5 | sourceType: 'module'
6 | },
7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
8 | extends: 'standard',
9 | // required to lint *.vue files
10 | plugins: [
11 | 'html'
12 | ],
13 | // add your custom rules here
14 | rules: {
15 | 'indent': ['warn', 4],
16 | 'semi': 0, // off semi
17 | 'eol-last': 0,
18 | 'no-unused-vars': 0,
19 | // allow paren-less arrow functions
20 | 'arrow-parens': 0,
21 | // allow async-await
22 | 'generator-star-spacing': 0,
23 | 'no-unused-vars': 0,
24 | // allow debugger during development
25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea
3 | node_modules/
4 | npm-debug.log
5 | test/unit/coverage
6 | test/e2e/reports
7 | selenium-debug.log
8 | /.idea
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vue-cli(2.0) 多页面开发实战
2 |
3 | > 由于之前主要使用jquery方式开发,现在想换一种方式,使用MVVM开发(感觉vue跟我之前用的angular1.X差不多类似),所以在开发中会遇到很多问题,借此来记录一下;或者有很多不足,又或者里面可能存在些错误,anyway,请多多指教,共勉。
4 |
5 | ## 现在的开发环境 ##
6 |
7 | 1. nodejs v5.1.1 ,npm 3.3.1.12
8 | 2. 使用vue-cli(包含vue2.0,webpack,sass,es6等环境)
9 |
10 | ## 如何运行项目 ##
11 |
12 | ``` bash
13 | # 下载项目后,首先安装需要的包
14 | npm install
15 |
16 | # 开发运行环境;运行命令后,浏览器自动打开http://localhost:8080/views/index.html
17 | npm run dev
18 |
19 | # 开发完成后打包命令,会生成dist文件夹,不要在本地打开,请安装类似http-server来运行(dist后js/css/api路径会指向我的github,可以在config/index.js下修改assetsPublicPath)
20 | npm run build
21 |
22 | ```
23 |
24 | ## 前期准备 ##
25 |
26 | 1. 选择一个多页面开发案例参考,结合自己的实际情况修改一下,这里主要参考了以下一些案例
27 | - [https://github.com/bluefox1688/vue-cli-multi-page](https://github.com/bluefox1688/vue-cli-multi-page)(参考多页面配置整体思想)
28 | - [https://github.com/jiananle/vue-multi-page](https://github.com/jiananle/vue-multi-page)(参考整个文件命名架构,比较适合我这种情况)
29 | - [https://github.com/jarvan4dev/vue-multi-page](https://github.com/jarvan4dev/vue-multi-page)(参考以模块名作为名字输出,避免以模块名里面的文件名作为名字输出导致覆盖)
30 |
31 | 2. 熟悉相关语法(基本了解就好,毕竟做项目的时候才会发现更多的问题)
32 | - [es6基本使用方法](http://es6.ruanyifeng.com/)
33 | - [vue2.0官网](https://cn.vuejs.org/v2/guide/),[vue2 api](https://cn.vuejs.org/v2/api/)
34 | - [sass基本语法](http://www.w3cplus.com/sassguide/)
35 |
36 | ## 遇到的问题及功能 ##
37 |
38 | - 引入资源路径不要写相对路径, 使用base.config.js中定义的alias,如index.vue
39 |
40 | ```
41 | import CommonFooter from '../../components/common/footer.vue'' => import CommonFooter from 'components/common/footer.vue'
42 |
43 |
46 | ```
47 |
48 | home.scss
49 |
50 | ```
51 | @import "../../../assets/scss/base/necessary.scss"; => @import "~assets/scss/base/necessary.scss";
52 |
53 | background: url(../../assets/images/icon/loading.gif) => background: url('~assets/images/icon/loading.gif')
54 | ```
55 |
56 | - 多页面SPA的组织架构重整 UPDATAE 201.6.11
57 |
58 | - mockjs模拟接口数据返回(Demo:删除购物车功能, 待点评列表)
59 |
60 | - [基于vue-cli,使用vue2.3.3 + webpack2 + es6 + vuex2.3.1 + scss的脚手架](https://github.com/luchanan/vue_cli_multiple_page)
61 |
62 | - 试用网站多语言支持(R5)
63 |
64 | - 刚开始装上vue-cli,发现eslint语法太过严格(定义未使用,要多少个空格,结尾要空行等),所以进行适当调整(M4)
65 |
66 | - eslint会对assets下面的第三方插件(自己下载引入的)也进行语法检测,有三种方法解决(A11)
67 |
68 | - .vue如何使用组件(A4)
69 |
70 | - .vue使用sass,注意是lang='scss'~~不是lang='sass'~~ 也可以是lang='sass (A5)
71 |
72 | - 如何npm一个带版本号的插件(A8)
73 |
74 | - 如何请求后台数据(vue-resource方式),并且渲染到html上(A12)
75 |
76 | - 微信jssdk如何设置全局,并且使用
77 |
78 | - 使用v:bind:style设置background(A13)
79 |
80 | - class使用多条件进行判断(A15)
81 |
82 | - 如何生成一个tree目录(额外内容)(A18)
83 |
84 | - html-loader部分代替服务器SSI(.html文件使用SSI来include类似JS或CSS资源目前没有找到很好的解决方法)(M1)
85 |
86 | - 子传父,父传子,非父子组件(BUS方式)之间传值问题(M8/M9/M10/M11)
87 |
88 | - set使用导致html{{}}无法输出2层 以上的object(M15)
89 |
90 | - img:src绑定assets下图片404问题(M9)
91 |
92 | ```
93 | // 使用
94 |
95 | ```
96 |
97 | - 使用filters(M12)
98 |
99 | - .js或.vue中script使用import(或require)文件引入.scss文件没有自动添加浏览器前缀问题,npm run dev 和npm run build 编译后浏览器前缀解析(丢失部分)不一样问题(M17)
100 |
101 | - ~~加入vuex逐步取代之前bus组件通讯方式,axios代替之前的vue-resource方案~~ 已全部代替(M18/M22)
102 |
103 | - 使用async/await来处理多个异步action且有依赖关系(M23)
104 |
105 | - dev模式下插入到html文件的script标签顺序没问题(例如,先是vendor.js里面包含vue,vuex集合,然后再是index.js),但是build后,顺序是反过来的,导致Cannot read property 'call' of undefined报错(M25)
106 |
107 | - iscroll5.2 在谷歌V56模拟器或者真机不能滑动的解决方案(M28)
108 |
109 | > 以上括号数字代表note/byluchanan.docx(没有特殊说明都是这个文件)里面的问题序号(蓝色下划线部分),R*代表.md文件名序号,更多详情看note文件下
110 |
111 | > 由于docx在git对比的不方便性,于2017/3/3 21:27结束编写,之后的问题以.md方式记录,放在note下
112 |
113 | ## 目前完成的模块 ##
114 |
115 | - 首页
116 |
117 | - 登录
118 |
119 | - 个人中心SPA包含我的、消息列表、我的收藏、客服页,设置,待点评
120 |
121 | - 目的地选择
122 |
123 | - 购物车列表
124 |
125 |
126 | ### 说明
127 |
128 | > 使用的图片资源,接口均来自chrome分析出来的,学习之用。
129 |
--------------------------------------------------------------------------------
/build/build.js:
--------------------------------------------------------------------------------
1 | // https://github.com/shelljs/shelljs
2 | require('shelljs/global')
3 | env.NODE_ENV = 'production'
4 |
5 | var path = require('path')
6 | var config = require('../config')
7 | var ora = require('ora')
8 | var webpack = require('webpack')
9 | var webpackConfig = require('./webpack.prod.conf')
10 |
11 | console.log(
12 | ' Tip:\n' +
13 | ' Built files are meant to be served over an HTTP server.\n' +
14 | ' Opening index.html over file:// won\'t work.\n'
15 | )
16 |
17 | var spinner = ora('building for production...')
18 | spinner.start()
19 |
20 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
21 |
22 | rm('-rf', assetsPath) // 删除 assetsPath(dist/static) 目录下的文件及目录, 忽略不存在的目录
23 | mkdir('-p', assetsPath) // 若路径中的某些目录尚不存在, 系统将自动建立好那些尚不存在的目录,即一次可以建立多个目录
24 | cp('-R', 'static/*', assetsPath) // 复制目录及目录内的所有项目
25 |
26 | webpack(webpackConfig, function (err, stats) {
27 | spinner.stop()
28 | if (err) throw err
29 | process.stdout.write(stats.toString({
30 | colors: true,
31 | modules: false,
32 | children: false,
33 | chunks: false,
34 | chunkModules: false
35 | }) + '\n')
36 | })
37 |
--------------------------------------------------------------------------------
/build/dev-client.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | require('eventsource-polyfill')
3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
4 |
5 | hotClient.subscribe(function (event) {
6 | if (event.action === 'reload') {
7 | window.location.reload()
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/build/dev-server.js:
--------------------------------------------------------------------------------
1 | var config = require('../config')
2 | if (!process.env.NODE_ENV) process.env.NODE_ENV = config.dev.env
3 | var path = require('path')
4 | var express = require('express')
5 | var webpack = require('webpack')
6 | var opn = require('opn')
7 | var proxyMiddleware = require('http-proxy-middleware')
8 | var webpackConfig = require('./webpack.dev.conf')
9 |
10 | // default port where dev server listens for incoming traffic
11 | var port = process.env.PORT || config.dev.port
12 | // Define HTTP proxies to your custom API backend
13 | // https://github.com/chimurai/http-proxy-middleware
14 | var proxyTable = config.dev.proxyTable
15 |
16 | var app = express()
17 | var compiler = webpack(webpackConfig)
18 |
19 | var devMiddleware = require('webpack-dev-middleware')(compiler, {
20 | publicPath: webpackConfig.output.publicPath,
21 | stats: {
22 | colors: true,
23 | chunks: false
24 | }
25 | })
26 |
27 | var hotMiddleware = require('webpack-hot-middleware')(compiler)
28 |
29 | // force page reload when html-webpack-plugin template changes
30 | compiler.plugin('compilation', function (compilation) {
31 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
32 | hotMiddleware.publish({ action: 'reload' })
33 | cb()
34 | })
35 | })
36 |
37 | // proxy api requests
38 | Object.keys(proxyTable).forEach(function (context) {
39 | var options = proxyTable[context]
40 | if (typeof options === 'string') {
41 | options = { target: options }
42 | }
43 | app.use(proxyMiddleware(context, options))
44 | })
45 |
46 | // handle fallback for HTML5 history API
47 | app.use(require('connect-history-api-fallback')())
48 |
49 | // serve webpack bundle output
50 | app.use(devMiddleware)
51 |
52 | // enable hot-reload and state-preserving
53 | // compilation error display
54 | app.use(hotMiddleware)
55 |
56 | // serve pure static assets
57 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
58 | app.use(staticPath, express.static('./static'))
59 |
60 | module.exports = app.listen(port, function (err) {
61 | if (err) {
62 | console.log(err)
63 | return
64 | }
65 | var uri = 'http://localhost:' + port + '/views/index.html' // 直接显示页面
66 | console.log('Listening at ' + uri + '\n')
67 | opn(uri)
68 | })
69 |
--------------------------------------------------------------------------------
/build/utils.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | // glob模块,用于读取webpack入口目录文件
3 | var glob = require('glob');
4 | var config = require('../config')
5 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
6 |
7 | /*
8 | * 返回静态资源路径(不需要被处理的资源)
9 | * project/static
10 | * */
11 | exports.assetsPath = function (_path) {
12 | var assetsSubDirectory = process.env.NODE_ENV === 'production'
13 | ? config.build.assetsSubDirectory
14 | : config.dev.assetsSubDirectory
15 | return path.posix.join(assetsSubDirectory, _path)
16 | }
17 |
18 | exports.cssLoaders = function (options) {
19 | options = options || {}
20 | // generate loader string to be used with extract text plugin
21 | function generateLoaders (loaders) {
22 | var sourceLoader = loaders.map(function (loader) {
23 | var extraParamChar;
24 |
25 | if (/\?/.test(loader)) {
26 | loader = loader.replace(/\?/, '-loader?')
27 | extraParamChar = '&'
28 | } else {
29 | loader = loader + '-loader'
30 | extraParamChar = '?'
31 | // 解决npm run dev 和 npm run build 编译后前缀不一样的问题
32 | if (loader === 'css-loader') {
33 | extraParamChar = '?-autoprefixer&'
34 | }
35 | }
36 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
37 |
38 | }).join('!');
39 |
40 | // Extract CSS when that option is specified
41 | // (which is the case during production build)
42 | if (options.extract) {
43 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader)
44 | } else {
45 | return ['vue-style-loader', sourceLoader].join('!')
46 | }
47 | }
48 |
49 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html
50 | return {
51 | css: generateLoaders(['css']),
52 | postcss: generateLoaders(['css']),
53 | less: generateLoaders(['css', 'less']),
54 | sass: generateLoaders(['css', 'sass?indentedSyntax']),
55 | scss: generateLoaders(['css', 'sass']),
56 | stylus: generateLoaders(['css', 'stylus']),
57 | styl: generateLoaders(['css', 'stylus'])
58 | }
59 | }
60 |
61 | // Generate loaders for standalone style files (outside of .vue)
62 | exports.styleLoaders = function (options) {
63 | var output = [];
64 | var loaders = exports.cssLoaders(options);
65 |
66 | for (var extension in loaders) {
67 | // var loader = loaders[extension];
68 | // 解决.js文件引入scss无法添加前缀问题
69 | var loader = loaders[extension].split('!');
70 | // 解决.js文件引入scss无法添加前缀问题
71 | var isPreProcesser = ['less', 'sass', 'scss' ,'stylus', 'styl'].some(function (v) {
72 | return v === extension
73 | })
74 | // 解决.js文件引入scss无法添加前缀问题
75 | if (isPreProcesser) {
76 | loader.splice(-1, 0, 'postcss-loader')
77 | }
78 | output.push({
79 | test: new RegExp('\\.' + extension + '$'),
80 | // loader: loader
81 | // 解决.js文件引入scss无法添加前缀问题
82 | loader: loader.join('!')
83 | })
84 | }
85 |
86 | return output
87 | }
88 | //获取js入口文件
89 | exports.getEntries = function (globPath,type) {
90 | var entries = {}
91 | var ishtml=type!==undefined?true:false;
92 | /**
93 | * 读取src目录,并进行路径裁剪
94 | */
95 | glob.sync(globPath).forEach(function (entry) {
96 | /**
97 | * path.basename 提取出用 ‘/' 隔开的path的最后一部分,除第一个参数外其余是需要过滤的字符串
98 | * path.extname 获取文件后缀
99 | */
100 | // var basename = path.basename(entry, path.extname(entry), 'router.js') // 过滤router.js
101 | // ***************begin***************
102 | // 当然, 你也可以加上模块名称, 即输出如下: { module/main: './src/module/index/main.js', module/test: './src/module/test/test.js' }
103 | // 最终编译输出的文件也在module目录下, 访问路径需要时 localhost:8080/module/index.html
104 | // slice 从已有的数组中返回选定的元素, -3 倒序选择,即选择最后三个
105 | //以ocahost:8080/homeIndex.html这样形式访问
106 | if(ishtml){
107 | //html以模块文件作为输出
108 | //以locahost:8080/views/index.html这样形式访问
109 | /*var tmp = entry.split('/').splice(-3)
110 | var moduleName = tmp.slice(0, 2).join("/");
111 | console.log(moduleName);
112 | entries[moduleName] = entry*/
113 | var tmp = entry.split('/').splice(-3)
114 | var moduleName = tmp.splice(0,2).join("/");
115 | entries[moduleName] = entry
116 |
117 | }
118 | else{
119 | //js以模块文件作为输出,比如indx.js
120 | var basename = path.basename(entry, path.extname(entry));
121 | tmp = entry.split('/').splice(-3);
122 | pathname = tmp.splice(1, 1);
123 | entries[pathname] = entry;
124 | }
125 | //以locahost:8080/views/index.html这样形式访问
126 | // var tmp = entry.split('/').splice(-3)
127 | // var moduleName = tmp.slice(1, 2);
128 | // console.log(moduleName);
129 | // entries[moduleName] = entry
130 | });
131 | // console.log(entries);
132 | // 获取的主入口如下: { main: './src/module/index/main.js', test: './src/module/test/test.js' }
133 | return entries;
134 | }
135 |
--------------------------------------------------------------------------------
/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var utils = require('./utils')
4 | var glob = require('glob')
5 | var autoprefixer = require('autoprefixer')
6 | var HtmlWebpackPlugin = require('html-webpack-plugin')
7 | var env = process.env.NODE_ENV
8 | // check env & config/index.js to decide weither to enable CSS Sourcemaps for the
9 | // various preprocessor loaders added to vue-loader at the end of this file
10 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
11 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
12 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd
13 |
14 | var projectRoot = path.resolve(__dirname, '../')
15 | var srcDir = path.resolve(__dirname, '../src')
16 | var entries = utils.getEntries(srcDir + '/views/**/*.js')
17 | var libs=path.resolve(__dirname, '../static/js/lib')
18 | entries['flexible'] = path.resolve(__dirname, libs+'/flexible/flexible.js')
19 | var autoprefixerConf = autoprefixer({ browsers: ['last 2 versions','Android >= 4.0','iOS >= 6'] });
20 |
21 | module.exports = {
22 | entry: entries,
23 |
24 | output: {
25 | path: config.build.assetsRoot,
26 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
27 | filename: '[name].js'
28 | },
29 |
30 | resolve: {
31 | extensions: ['', '.js', '.vue'],
32 | fallback: [path.join(__dirname, '../node_modules')],
33 | alias: {
34 | 'vue$': 'vue/dist/vue',
35 | // 'jquery$': 'jquery/dist/jquery',// 注销,使用CDN
36 | 'src': path.resolve(__dirname, '../src'),
37 | 'assets': path.resolve(__dirname, '../src/assets'),
38 | 'images': path.resolve(__dirname, '../src/assets/images'),
39 | 'js': path.resolve(__dirname, '../src/assets/js'),
40 | 'components': path.resolve(__dirname, '../src/components'),
41 | 'scss': path.resolve(__dirname, '../src/assets/scss')
42 | }
43 | },
44 |
45 | resolveLoader: {
46 | fallback: [path.join(__dirname, '../node_modules')]
47 | },
48 | externals: {
49 | 'wx': 'jWeixin', // 使用cdn资源,暴露wx
50 | 'jquery': 'jQuery' // 使用cdn资源,暴露jquery
51 | },
52 | module: {
53 | preLoaders: [
54 | {
55 | test: /\.vue$/,
56 | loader: 'eslint',
57 | include: projectRoot,
58 | exclude: /node_modules/
59 | },
60 | {
61 | test: /\.js$/,
62 | loader: 'eslint',
63 | include: projectRoot,
64 | exclude: /node_modules/
65 | }
66 | ],
67 |
68 | loaders: [
69 | {
70 | test: /\.vue$/,
71 | loader: 'vue'
72 | },
73 | {
74 | test: /\.js$/,
75 | loader: 'babel',
76 | include: projectRoot,
77 | exclude: /node_modules/
78 | },
79 | {
80 | test: /\.html$/,
81 | loader: 'html'
82 | },
83 | {
84 | test: /\.json$/,
85 | loader: 'json'
86 | },
87 | /*{
88 | test: /\.(css|scss)$/,
89 | loader: "style!css!postcss!sass"
90 | },*/
91 | {
92 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
93 | loader: 'url',
94 | query: {
95 | limit: 10000,
96 | name: utils.assetsPath('images/[name].[hash:7].[ext]')
97 | }
98 | },
99 | {
100 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
101 | loader: 'url',
102 | query: {
103 | limit: 10000,
104 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
105 | }
106 | }
107 | ]
108 | },
109 | // js 中引入的样式处理
110 | postcss: [autoprefixerConf],
111 | eslint: {
112 | formatter: require('eslint-friendly-formatter')
113 | },
114 | vue: {
115 | // .vue 中的样式处理
116 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }),
117 | postcss: [autoprefixerConf]
118 | },
119 | plugins:[]
120 | }
121 | var pages = utils.getEntries('./src/views/**/*.html',1);
122 |
123 | for (var pathname in pages) {
124 | // 生成html相关配置
125 | var conf = {
126 | filename: pathname + '.html', // html文件输出路径
127 | template: pages[pathname], // 模板路径
128 | inject: true, // js插入位置
129 | minify: {
130 | //压缩设置
131 | //removeComments: true,
132 | //collapseWhitespace: true,
133 | //removeAttributeQuotes: true
134 | // more options:
135 | // https://github.com/kangax/html-minifier#options-quick-reference
136 | },
137 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
138 | chunksSortMode: 'dependency'
139 | };
140 | pathname=pathname.split("/")[1];//去掉views
141 | if (pathname in module.exports.entry) {
142 | conf.inject = 'body';
143 | //如果每个html没有进入这里的话,那么全部js将会插入html
144 | conf.chunks = ['flexible', pathname, 'vendor', 'manifest', 'bootstrap'],
145 | conf.hash = true;
146 | }
147 | module.exports.plugins.push(new HtmlWebpackPlugin(conf));
148 | }
149 |
--------------------------------------------------------------------------------
/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack')
2 | var merge = require('webpack-merge')
3 | var config = require('../config')
4 | var utils = require('./utils')
5 | var baseWebpackConfig = require('./webpack.base.conf')
6 |
7 | // add hot-reload related code to entry chunks
8 | Object.keys(baseWebpackConfig.entry).forEach(function (name) {
9 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
10 | })
11 |
12 |
13 | var devConf = merge(baseWebpackConfig, {
14 | module: {
15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
16 | },
17 | // eval-source-map is faster for development
18 | devtool: '#eval-source-map',
19 | plugins: [
20 | new webpack.DefinePlugin({
21 | 'process.env': config.dev.env
22 | }),
23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
24 | new webpack.optimize.OccurenceOrderPlugin(),
25 | new webpack.HotModuleReplacementPlugin(),
26 | new webpack.NoErrorsPlugin(),
27 | ]
28 | })
29 |
30 | module.exports = devConf;
31 |
--------------------------------------------------------------------------------
/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var webpack = require('webpack')
3 | var merge = require('webpack-merge')
4 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | var utils = require('./utils')
6 | var config = require('../config')
7 | var baseWebpackConfig = require('./webpack.base.conf')
8 | var env = config.build.env;
9 |
10 |
11 | var webpackConfig = merge(baseWebpackConfig, {
12 | module: {
13 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true })
14 | },
15 |
16 | devtool: config.build.productionSourceMap ? '#source-map' : false,
17 |
18 | output: {
19 | path: config.build.assetsRoot,
20 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
22 | },
23 |
24 | vue: {
25 | loaders: utils.cssLoaders({
26 | sourceMap: config.build.productionSourceMap,
27 | extract: true
28 | })
29 | },
30 |
31 | plugins: [
32 | // http://vuejs.github.io/vue-loader/workflow/production.html
33 | new webpack.DefinePlugin({
34 | 'process.env': env
35 | }),
36 |
37 | new webpack.optimize.UglifyJsPlugin({
38 | compress: {
39 | warnings: false
40 | }
41 | }),
42 | // 有时候build出来的