├── static
└── .gitkeep
├── src
├── device
│ ├── mobile
│ │ ├── index.js
│ │ └── index.html
│ ├── pc
│ │ ├── api
│ │ │ ├── middleware.js
│ │ │ └── home.js
│ │ ├── components
│ │ │ ├── Page404
│ │ │ │ └── Index.vue
│ │ │ ├── Home
│ │ │ │ ├── Body.vue
│ │ │ │ └── Index.vue
│ │ │ └── commonComponents
│ │ │ │ └── Header.vue
│ │ ├── index.html
│ │ ├── types
│ │ │ ├── root.js
│ │ │ └── home.js
│ │ ├── index.js
│ │ ├── router
│ │ │ └── index.js
│ │ ├── App.vue
│ │ └── store
│ │ │ ├── index.js
│ │ │ └── modules
│ │ │ └── home.js
│ └── app
│ │ ├── index.js
│ │ └── index.html
├── assets
│ └── logo.png
├── api
│ ├── middleware.js
│ └── device-root.js
├── config.js
└── components
│ └── RootCommonComponent.vue
├── .eslintignore
├── config
├── prod.env.js
├── test.env.js
├── dev.env.js
└── index.js
├── tree.txt
├── images
├── icon.png
├── show.gif
├── build.png
├── build-pc.png
├── pc-index.png
├── view-com.png
├── run-dev-url.png
├── vuex-api-com.png
└── whole-view.png
├── test
├── unit
│ ├── .eslintrc
│ ├── specs
│ │ └── Hello.spec.js
│ ├── index.js
│ └── karma.conf.js
└── e2e
│ ├── specs
│ └── test.js
│ ├── custom-assertions
│ └── elementCount.js
│ ├── runner.js
│ └── nightwatch.conf.js
├── .gitignore
├── .editorconfig
├── .postcssrc.js
├── index.html
├── .babelrc
├── .eslintrc.js
├── sever
└── prod-view-server.js
├── package.json
└── README.md
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/device/mobile/index.js:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | config/*.js
3 |
--------------------------------------------------------------------------------
/src/device/pc/api/middleware.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里是pc这个模块的接口的中间件
3 | */
4 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/src/device/app/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Administrator on 2017/5/19.
3 | */
4 |
--------------------------------------------------------------------------------
/tree.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/tree.txt
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/icon.png
--------------------------------------------------------------------------------
/images/show.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/show.gif
--------------------------------------------------------------------------------
/images/build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/build.png
--------------------------------------------------------------------------------
/images/build-pc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/build-pc.png
--------------------------------------------------------------------------------
/images/pc-index.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/pc-index.png
--------------------------------------------------------------------------------
/images/view-com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/view-com.png
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/images/run-dev-url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/run-dev-url.png
--------------------------------------------------------------------------------
/images/vuex-api-com.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/vuex-api-com.png
--------------------------------------------------------------------------------
/images/whole-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentmrlau/vue-multi-device-single-page/HEAD/images/whole-view.png
--------------------------------------------------------------------------------
/test/unit/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "mocha": true
4 | },
5 | "globals": {
6 | "expect": true,
7 | "sinon": true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/config/test.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var devEnv = require('./dev.env')
3 |
4 | module.exports = merge(devEnv, {
5 | NODE_ENV: '"testing"'
6 | })
7 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | test/unit/coverage
8 | test/e2e/reports
9 | selenium-debug.log
10 | /.idea
11 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | // to edit target browsers: use "browserlist" field in package.json
6 | "autoprefixer": {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/device/pc/components/Page404/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
404页
4 | 点我回到首页
5 |
6 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/src/api/middleware.js:
--------------------------------------------------------------------------------
1 | // 这里放公用的中间件
2 |
3 | export const SET_AUTHORIZATION = (request, next) => {
4 | // 处理请求
5 | request.headers.set('Authorization', 'vincent')
6 | next((response) => {
7 | // 处理返回的数据
8 | console.log(response)
9 | })
10 | }
11 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | vue-multi-single-page
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", { "modules": false }],
4 | "stage-2"
5 | ],
6 | "plugins": ["transform-runtime"],
7 | "comments": false,
8 | "env": {
9 | "test": {
10 | "presets": ["env", "stage-2"],
11 | "plugins": [ "istanbul" ]
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里放全局的配置文件
3 | */
4 |
5 | // 请求域名
6 | const PRODUCTION_HOSTNAME = 'http://localhost:3000'
7 | const DEVELOPMENT_HOSTNAME = 'http://localhost:3000'
8 | export const ROOT_HOST_NAME = process.env.NODE_ENV === 'production'
9 | ? PRODUCTION_HOSTNAME
10 | : DEVELOPMENT_HOSTNAME
11 |
--------------------------------------------------------------------------------
/src/device/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | vue-multi-single-page-app
6 |
7 |
8 | 来自app/index.html的内容
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/device/pc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | vue-multi-single-page-pc
6 |
7 |
8 | 来自pc/index.html的内容,我仅仅是个用来打包的模板
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/device/mobile/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | vue-multi-single-page-mobile
6 |
7 |
8 | 来自mobile/index.html的内容
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/components/RootCommonComponent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 本宝宝来自/src/components/RootCommonComponent.vue,
4 | 被devie目录下的任何端使用我都没有所谓(*^__^*)
5 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/src/device/pc/types/root.js:
--------------------------------------------------------------------------------
1 | // 根级别的方法命名
2 | // 命名规则示例
3 | // ROOT_S_COUNT
4 | // ROOT:属于跟级别的
5 | // S:STATE缩写;其他的类似,如G:GETTER
6 | // COUNT:属性名
7 |
8 | export const ROOT_S_COUNT = 'ROOT_S_COUNT'
9 | export const ROOT_G_COUNT = 'ROOT_G_COUNT'
10 | export const ROOT_M_INCREMENT = 'ROOT_M_INCREMENT'
11 | export const ROOT_A_INCREMENT = 'ROOT_A_INCREMENT'
12 |
13 |
--------------------------------------------------------------------------------
/src/device/pc/components/Home/Body.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 终于轮到我了,来自/src/device/pc/components/home/Body.vue,
4 | 我比较适合被device/pc/home下的组件使用(*^__^*)
5 |
6 |
7 |
8 |
13 |
14 |
19 |
--------------------------------------------------------------------------------
/test/unit/specs/Hello.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Hello from '@/components/Hello'
3 |
4 | describe('Hello.vue', () => {
5 | it('should render correct contents', () => {
6 | const Constructor = Vue.extend(Hello)
7 | const vm = new Constructor().$mount()
8 | expect(vm.$el.querySelector('.hello h1').textContent)
9 | .to.equal('Welcome to Your Vue.js App')
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/src/device/pc/components/commonComponents/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 本宝宝来自/src/device/pc/components/commonComponents/Header.vue,
4 | 我比较适合被device/pc/下的页面使用,其他的要搞我我就╭(╯^╰)╮
5 |
6 |
7 |
8 |
13 |
14 |
19 |
--------------------------------------------------------------------------------
/src/device/pc/index.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App.vue'
5 | import router from './router'
6 | import store from './store'
7 |
8 | Vue.config.productionTip = false
9 |
10 | /* eslint-disable no-new */
11 | new Vue({
12 | el: '#app',
13 | router,
14 | store,
15 | template: '',
16 | components: { App }
17 | })
18 |
--------------------------------------------------------------------------------
/src/device/pc/types/home.js:
--------------------------------------------------------------------------------
1 | // home模块的方法命名
2 | // 命名规则示例
3 | // HOME_S_COUNT
4 | // HOME:属于跟级别的
5 | // S:STATE缩写;其他的类似,如G:GETTER
6 | // COUNT:属性名
7 |
8 | export const HOME_S_AUTH = 'HOME_S_AUTH'
9 | export const HOME_G_AUTH = 'HOME_G_AUTH'
10 | export const HOME_M_AUTH = 'HOME_M_AUTH'
11 | export const HOME_A_AUTH = 'HOME_A_AUTH'
12 | export const HOME_A_ROOT_COUNT = 'HOME_A_ROOT_COUNT'
13 | export const HOME_A_GET_AUTH = 'HOME_A_GET_AUTH'
14 | export const HOME_A_SERVER_COUNT = 'HOME_A_SERVER_COUNT'
15 |
--------------------------------------------------------------------------------
/src/device/pc/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | const Home = resolve => require(['./../components/Home/Index.vue'], resolve)
7 | const Page404 = resolve => require(['./../components/Page404/Index.vue'], resolve)
8 |
9 | export default new Router({
10 | routes: [
11 | {
12 | path: '/',
13 | name: 'Home',
14 | component: Home
15 | },
16 | {
17 | path: '*',
18 | name: 'Page404',
19 | component: Page404
20 | }
21 | ]
22 | })
23 |
--------------------------------------------------------------------------------
/test/unit/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | Vue.config.productionTip = false
4 |
5 | // require all test files (files that ends with .spec.js)
6 | const testsContext = require.context('./specs', true, /\.spec$/)
7 | testsContext.keys().forEach(testsContext)
8 |
9 | // require all src files except index.js for coverage.
10 | // you can also change this to match only the subset of files that
11 | // you want coverage for.
12 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
13 | srcContext.keys().forEach(srcContext)
14 |
--------------------------------------------------------------------------------
/src/api/device-root.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里放公用的api
3 | * 可以被不同的device使用
4 | */
5 | import Vue from 'vue'
6 | import vueResource from 'vue-resource'
7 |
8 | // 引入中间件
9 | import {SET_AUTHORIZATION} from './middleware'
10 | // 引入配置端口
11 | import {ROOT_HOST_NAME} from './../config'
12 |
13 | Vue.use(vueResource)
14 | Vue.http.options.crossOrigin = true
15 |
16 | // 使用中间件
17 | Vue.http.interceptors.push(SET_AUTHORIZATION)
18 |
19 | // 输出方法
20 | export const ROOT_API_GET_AUTH = function (data, options = {}) {
21 | return Vue.http.post(ROOT_HOST_NAME + '/getAuth', data, {
22 | ...options
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/src/device/pc/api/home.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 这里是pc的home这个模块的api
3 | * */
4 |
5 | import Vue from 'vue'
6 | import vueResource from 'vue-resource'
7 |
8 | // 引入中间件
9 | import {SET_AUTHORIZATION} from './middleware'
10 | // 引入配置端口
11 | import {ROOT_HOST_NAME} from './../../../config'
12 |
13 | Vue.use(vueResource)
14 | Vue.http.options.crossOrigin = true
15 |
16 | // 使用根级别的中间件
17 | Vue.http.interceptors.push(SET_AUTHORIZATION)
18 |
19 | // 输出方法
20 | export const HOME_API_COUNT = function (params, options = {}) {
21 | return Vue.http.get(ROOT_HOST_NAME + '/count', {
22 | params: params,
23 | ...options
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/src/device/pc/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
22 |
23 |
32 |
--------------------------------------------------------------------------------
/test/e2e/specs/test.js:
--------------------------------------------------------------------------------
1 | // For authoring Nightwatch tests, see
2 | // http://nightwatchjs.org/guide#usage
3 |
4 | module.exports = {
5 | 'default e2e tests': function (browser) {
6 | // automatically uses dev Server port from /config.pc.js
7 | // default: http://localhost:8080
8 | // see nightwatch.conf.js
9 | const devServer = browser.globals.devServerURL
10 |
11 | browser
12 | .url(devServer)
13 | .waitForElementVisible('#app', 5000)
14 | .assert.elementPresent('.hello')
15 | .assert.containsText('h1', 'Welcome to Your Vue.js App')
16 | .assert.elementCount('img', 1)
17 | .end()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // http://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parser: 'babel-eslint',
6 | parserOptions: {
7 | sourceType: 'module'
8 | },
9 | env: {
10 | browser: true,
11 | },
12 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
13 | extends: 'standard',
14 | // required to lint *.vue files
15 | plugins: [
16 | 'html'
17 | ],
18 | // add your custom rules here
19 | 'rules': {
20 | // allow paren-less arrow functions
21 | 'arrow-parens': 0,
22 | // allow async-await
23 | 'generator-star-spacing': 0,
24 | // allow debugger during development
25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/device/pc/store/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里存放pc的根级别的 store mutation action 和组装模块并导出
3 | */
4 |
5 | import Vue from 'vue'
6 | import Vuex from 'vuex'
7 |
8 | // 引入type
9 | import * as rootTypes from './../types/root'
10 | // 引入模块
11 | import home from './modules/home.js'
12 |
13 | Vue.use(Vuex)
14 |
15 | export default new Vuex.Store({
16 | state: {
17 | [rootTypes.ROOT_S_COUNT]: 0
18 | },
19 | getters: {
20 | [rootTypes.ROOT_G_COUNT]: state => state[rootTypes.ROOT_S_COUNT]
21 | },
22 | mutations: {
23 | [rootTypes.ROOT_M_INCREMENT]: (state, payload) => {
24 | state[rootTypes.ROOT_S_COUNT] += payload.add
25 | }
26 | },
27 | actions: {
28 | [rootTypes.ROOT_A_INCREMENT]: ({commit}) => {
29 | commit({
30 | type: rootTypes.ROOT_M_INCREMENT,
31 | add: 2
32 | })
33 | }
34 | },
35 | modules: {
36 | home
37 | }
38 | })
39 |
--------------------------------------------------------------------------------
/test/e2e/custom-assertions/elementCount.js:
--------------------------------------------------------------------------------
1 | // A custom Nightwatch assertion.
2 | // the name of the method is the filename.
3 | // can be used in tests like this:
4 | //
5 | // browser.assert.elementCount(selector, count)
6 | //
7 | // for how to write custom assertions see
8 | // http://nightwatchjs.org/guide#writing-custom-assertions
9 | exports.assertion = function (selector, count) {
10 | this.message = 'Testing if element <' + selector + '> has count: ' + count
11 | this.expected = count
12 | this.pass = function (val) {
13 | return val === this.expected
14 | }
15 | this.value = function (res) {
16 | return res.value
17 | }
18 | this.command = function (cb) {
19 | var self = this
20 | return this.api.execute(function (selector) {
21 | return document.querySelectorAll(selector).length
22 | }, [selector], function (res) {
23 | cb.call(self, res)
24 | })
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/sever/prod-view-server.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 用于预览打包后的产品的服务器
3 | */
4 | 'use strict'
5 | const express = require('express')
6 | const opn = require('opn')
7 | const bodyParser = require('body-parser')
8 |
9 | let app = express()
10 | app.use(bodyParser())
11 | app.all('*', function (req, res, next) {
12 | res.header('Access-Control-Allow-Origin', '*');
13 | res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With');
14 | res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
15 | if (req.method == 'OPTIONS') {
16 | res.send(200);
17 | } else {
18 | next();
19 | }
20 | });
21 |
22 | app.use('/',express.static('./dist/'))
23 |
24 | app.post('/getAuth', (req, res, next) => {
25 | res.json({
26 | 'Auth': 'Vincent-sever-coder',
27 | 'recHeader': req.get('Authorization')
28 | })
29 | })
30 |
31 | app.get('/count', (req, res, next) => {
32 | res.json({
33 | count: 10
34 | })
35 | })
36 |
37 | app.listen('3000', () => {
38 | console.log('listen AT :3000')
39 | opn('http://localhost:3000/')
40 | })
41 |
--------------------------------------------------------------------------------
/test/unit/karma.conf.js:
--------------------------------------------------------------------------------
1 | // This is a karma config file. For more details see
2 | // http://karma-runner.github.io/0.13/config/configuration-file.html
3 | // we are also using it with karma-webpack
4 | // https://github.com/webpack/karma-webpack
5 |
6 | var webpackConfig = require('../../build/webpack.test.conf')
7 |
8 | module.exports = function (config) {
9 | config.set({
10 | // to run in additional browsers:
11 | // 1. install corresponding karma launcher
12 | // http://karma-runner.github.io/0.13/config/browsers.html
13 | // 2. add it to the `browsers` array below.
14 | browsers: ['PhantomJS'],
15 | frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
16 | reporters: ['spec', 'coverage'],
17 | files: ['./index.js'],
18 | preprocessors: {
19 | './index.js': ['webpack', 'sourcemap']
20 | },
21 | webpack: webpackConfig,
22 | webpackMiddleware: {
23 | noInfo: true
24 | },
25 | coverageReporter: {
26 | dir: './coverage',
27 | reporters: [
28 | { type: 'lcov', subdir: '.' },
29 | { type: 'text-summary' }
30 | ]
31 | }
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/test/e2e/runner.js:
--------------------------------------------------------------------------------
1 | // 1. start the dev server using production config
2 | process.env.NODE_ENV = 'testing'
3 | var server = require('../../build/dev-server.js')
4 |
5 | server.ready.then(() => {
6 | // 2. run the nightwatch test suite against it
7 | // to run in additional browsers:
8 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings"
9 | // 2. add it to the --env flag below
10 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
11 | // For more information on Nightwatch's config file, see
12 | // http://nightwatchjs.org/guide#settings-file
13 | var opts = process.argv.slice(2)
14 | if (opts.indexOf('--config') === -1) {
15 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js'])
16 | }
17 | if (opts.indexOf('--env') === -1) {
18 | opts = opts.concat(['--env', 'chrome'])
19 | }
20 |
21 | var spawn = require('cross-spawn')
22 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })
23 |
24 | runner.on('exit', function (code) {
25 | server.close()
26 | process.exit(code)
27 | })
28 |
29 | runner.on('error', function (err) {
30 | server.close()
31 | throw err
32 | })
33 | })
34 |
--------------------------------------------------------------------------------
/test/e2e/nightwatch.conf.js:
--------------------------------------------------------------------------------
1 | require('babel-register')
2 | var config = require('../../config')
3 |
4 | // http://nightwatchjs.org/gettingstarted#settings-file
5 | module.exports = {
6 | src_folders: ['test/e2e/specs'],
7 | output_folder: 'test/e2e/reports',
8 | custom_assertions_path: ['test/e2e/custom-assertions'],
9 |
10 | selenium: {
11 | start_process: true,
12 | server_path: require('selenium-server').path,
13 | host: '127.0.0.1',
14 | port: 4444,
15 | cli_args: {
16 | 'webdriver.chrome.driver': require('chromedriver').path
17 | }
18 | },
19 |
20 | test_settings: {
21 | default: {
22 | selenium_port: 4444,
23 | selenium_host: 'localhost',
24 | silent: true,
25 | globals: {
26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port)
27 | }
28 | },
29 |
30 | chrome: {
31 | desiredCapabilities: {
32 | browserName: 'chrome',
33 | javascriptEnabled: true,
34 | acceptSslCerts: true
35 | }
36 | },
37 |
38 | firefox: {
39 | desiredCapabilities: {
40 | browserName: 'firefox',
41 | javascriptEnabled: true,
42 | acceptSslCerts: true
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/device/pc/store/modules/home.js:
--------------------------------------------------------------------------------
1 | // 这里写home这个模块的 store
2 | import * as homeTypes from './../../types/home'
3 | import * as rootTypes from './../../types/root'
4 |
5 | // 引入一个全局的api
6 | import {ROOT_API_GET_AUTH} from './../../../../api/device-root'
7 | // 引入一个属于这个模块的api
8 | import {HOME_API_COUNT} from './../../api/home'
9 | export default {
10 | state: {
11 | [homeTypes.HOME_S_AUTH]: '不存在的'
12 | },
13 | getters: {
14 | [homeTypes.HOME_G_AUTH]: (states) => {
15 | return states[homeTypes.HOME_S_AUTH]
16 | }
17 | },
18 | mutations: {
19 | [homeTypes.HOME_M_AUTH]: (states, payload) => {
20 | states[homeTypes.HOME_S_AUTH] = payload.auth
21 | }
22 | },
23 | actions: {
24 | [homeTypes.HOME_A_ROOT_COUNT]: ({commit}) => {
25 | return commit({
26 | type: rootTypes.ROOT_M_INCREMENT,
27 | add: 3
28 | })
29 | },
30 | [homeTypes.HOME_A_GET_AUTH]: ({commit}) => {
31 | console.log('HOME_A_GET_AUTH')
32 | ROOT_API_GET_AUTH({'TEST': 'BODY_STR'}).then(response => {
33 | // 请求成功
34 | console.log('ROOT_API_GET_AUTH done!', response)
35 | commit({
36 | type: homeTypes.HOME_M_AUTH,
37 | auth: response.body.Auth
38 | })
39 | }, response => {
40 | console.log('ROOT_API_GET_AUTH fail!', response)
41 | })
42 | },
43 | [homeTypes.HOME_A_SERVER_COUNT]: ({commit}) => {
44 | HOME_API_COUNT({'PRAMA_TEST': 'PRAMA1_STR'}).then(response => {
45 | // 成功
46 | console.log('HOME_API_COUNT done', response)
47 | commit({
48 | type: rootTypes.ROOT_M_INCREMENT,
49 | add: response.body.count
50 | })
51 | }, response => {
52 | // 失败
53 | console.log('HOME_API_COUNT fail', response)
54 | })
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 | var device = process.env.DEVICE_ENV || 'undefined'
4 |
5 |
6 | // 入口模板路径
7 | var htmlTemplate = './src/device/' + device + '/index.html'
8 |
9 | module.exports = {
10 | build: {
11 | env: require('./prod.env'),
12 | // 加入html入口
13 | htmlTemplate: htmlTemplate,
14 | index: path.resolve(__dirname, '../dist' , device , 'index.html'),
15 | assetsRoot: path.resolve(__dirname, '../dist' , device),
16 | assetsSubDirectory: 'static',
17 | // 这里的路径改成相对路径
18 | // 原来是: assetsPublicPath: '/',
19 | assetsPublicPath: '',
20 | productionSourceMap: true,
21 | // Gzip off by default as many popular static hosts such as
22 | // Surge or Netlify already gzip all static assets for you.
23 | // Before setting to `true`, make sure to:
24 | // npm install --save-dev compression-webpack-plugin
25 | productionGzip: false,
26 | productionGzipExtensions: ['js', 'css'],
27 | // Run the build command with an extra argument to
28 | // View the bundle analyzer report after build finishes:
29 | // `npm run build --report`
30 | // Set to `true` or `false` to always turn it on or off
31 | bundleAnalyzerReport: process.env.npm_config_report
32 | },
33 | dev: {
34 | env: require('./dev.env'),
35 | port: 8080,
36 | autoOpenBrowser: true,
37 | assetsSubDirectory: 'static',
38 | assetsPublicPath: '/',
39 | proxyTable: {},
40 | // CSS Sourcemaps off by default because relative paths are "buggy"
41 | // with this option, according to the CSS-Loader README
42 | // (https://github.com/webpack/css-loader#sourcemaps)
43 | // In our experience, they generally work as expected,
44 | // just be aware of this issue when enabling this option.
45 | cssSourceMap: false
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/device/pc/components/Home/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <_Header/>
5 | <_Body/>
6 |
{{msg}}
7 | 来自/pc/store/index.js的state 通过/pc/store/index.js的getter获取,count:{{count}}
8 |
9 |
10 |
11 |
12 |
13 | 来自/pc/store/home.js的state,通过/pc/store/home.js的getter获取, auth: {{auth}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
56 |
57 |
70 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-multi-single-page",
3 | "version": "1.0.0",
4 | "description": "hybrid multi page & single page Vue object",
5 | "author": "Vincent Lau 413893093@qq.com",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node build/dev-server.js",
9 | "start": "node build/dev-server.js",
10 | "build": "node build/build.js",
11 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
12 | "e2e": "node test/e2e/runner.js",
13 | "test": "npm run unit && npm run e2e",
14 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
15 | "build-all": "node build/build-all.js"
16 | },
17 | "dependencies": {
18 | "vue": "^2.2.6",
19 | "vue-resource": "^1.3.1",
20 | "vue-router": "^2.3.1",
21 | "vuex": "^2.3.1"
22 | },
23 | "devDependencies": {
24 | "autoprefixer": "^6.7.2",
25 | "babel-core": "^6.22.1",
26 | "babel-eslint": "^7.1.1",
27 | "babel-loader": "^6.2.10",
28 | "babel-plugin-istanbul": "^4.1.1",
29 | "babel-plugin-transform-runtime": "^6.22.0",
30 | "babel-polyfill": "^6.23.0",
31 | "babel-preset-env": "^1.3.2",
32 | "babel-preset-stage-2": "^6.22.0",
33 | "babel-register": "^6.22.0",
34 | "body-parser": "^1.17.2",
35 | "chai": "^3.5.0",
36 | "chalk": "^1.1.3",
37 | "child_process": "^1.0.2",
38 | "chromedriver": "^2.27.2",
39 | "colors": "^1.1.2",
40 | "connect-history-api-fallback": "^1.3.0",
41 | "copy-webpack-plugin": "^4.0.1",
42 | "cross-env": "^4.0.0",
43 | "cross-spawn": "^5.0.1",
44 | "css-loader": "^0.28.0",
45 | "eslint": "^3.19.0",
46 | "eslint-config-standard": "^6.2.1",
47 | "eslint-friendly-formatter": "^2.0.7",
48 | "eslint-loader": "^1.7.1",
49 | "eslint-plugin-html": "^2.0.0",
50 | "eslint-plugin-promise": "^3.4.0",
51 | "eslint-plugin-standard": "^2.0.1",
52 | "eventsource-polyfill": "^0.9.6",
53 | "express": "^4.14.1",
54 | "extract-text-webpack-plugin": "^2.0.0",
55 | "file-loader": "^0.11.1",
56 | "friendly-errors-webpack-plugin": "^1.1.3",
57 | "fs": "0.0.1-security",
58 | "glob": "^7.1.1",
59 | "html-webpack-plugin": "^2.28.0",
60 | "http-proxy-middleware": "^0.17.3",
61 | "inject-loader": "^3.0.0",
62 | "karma": "^1.4.1",
63 | "karma-coverage": "^1.1.1",
64 | "karma-mocha": "^1.3.0",
65 | "karma-phantomjs-launcher": "^1.0.2",
66 | "karma-phantomjs-shim": "^1.4.0",
67 | "karma-sinon-chai": "^1.3.1",
68 | "karma-sourcemap-loader": "^0.3.7",
69 | "karma-spec-reporter": "0.0.30",
70 | "karma-webpack": "^2.0.2",
71 | "lolex": "^1.5.2",
72 | "mocha": "^3.2.0",
73 | "nightwatch": "^0.9.12",
74 | "node-sass": "^4.5.3",
75 | "opn": "^4.0.2",
76 | "optimize-css-assets-webpack-plugin": "^1.3.0",
77 | "ora": "^1.2.0",
78 | "path": "^0.12.7",
79 | "phantomjs-prebuilt": "^2.1.14",
80 | "rimraf": "^2.6.0",
81 | "sass-loader": "^6.0.5",
82 | "selenium-server": "^3.0.1",
83 | "semver": "^5.3.0",
84 | "shelljs": "^0.7.6",
85 | "sinon": "^2.1.0",
86 | "sinon-chai": "^2.8.0",
87 | "url-loader": "^0.5.8",
88 | "vue-loader": "^11.3.4",
89 | "vue-style-loader": "^2.0.5",
90 | "vue-template-compiler": "^2.2.6",
91 | "webpack": "^2.3.3",
92 | "webpack-bundle-analyzer": "^2.2.1",
93 | "webpack-dev-middleware": "^1.10.0",
94 | "webpack-hot-middleware": "^2.18.0",
95 | "webpack-merge": "^4.1.0"
96 | },
97 | "engines": {
98 | "node": ">= 4.0.0",
99 | "npm": ">= 3.0.0"
100 | },
101 | "browserslist": [
102 | "> 1%",
103 | "last 2 versions",
104 | "not ie <= 8"
105 | ]
106 | }
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-multi-device-single-page
2 | > 多个单页应用整合的vue工程的开发环境
3 | > vue工程的目录设置
4 |
5 | [](https://cn.vuejs.org/) [](https://cn.vuejs.org/) [](https://github.com/pagekit/vue-resource/blob/develop/docs/http.md) [](https://cn.vuejs.org/) [](https://cn.vuejs.org/)
6 |
7 | ## 本文内容:
8 | 1. vue + vuex + vue-resuorce + vue-route 的工程 的目录设计
9 | 2. 基于 vue-cli 的 多个vue单页应用的开发环境 搭建
10 | ## 目录:
11 | > 一、开发环境使用
12 | >
13 | > 二、需求分析
14 | >
15 | > 三、开发思路
16 | >
17 | > 四、src目录设计及思路
18 | >
19 | > 五、开发环境开发
20 | >
21 | > 六、整个开发环境的目录注释
22 |
23 | ## 一、开发环境使用
24 |
25 | #### 多终端(页面)路径设置
26 | 1. 在src/device/目录下添加终端(页面)路径,如:src/device/pc/
27 | 2. 在新添加的文件下加入这个终端(页面)使用的打包模板,命名为index.html,如:src/device/pc/index.html
28 | 3. 在新添加的文件下加入这个终端(页面)使用的入口文件,命名为index.js,如:src/device/pc/index.js
29 |
30 | #### build 打包
31 | > 打生产环境的包,会自动把不同终端的文件按终端名称分开
32 |
33 | 
34 | > npm run build 'device'
35 | >
36 | > device : 接受的参数,在 `/build/device-conf.js`里面有限制
37 | >
38 | > 示例: `npm run build pc` 打一个pc端的包
39 |
40 | > npm run build-all
41 | >
42 | > 打所有终端的包
43 |
44 | #### dev 开发
45 | > npm run dev
46 | >
47 | > 开始进行调试,基于vue-cli的,所以基本是vue-cli的
48 |
49 | 1. 自动打开一个网页,从这里选择要调试的终端
50 |
51 | 
52 |
53 | 2. 开始调试
54 |
55 | 
56 |
57 | ## 二、需求分析:
58 | #### 需求:
59 | 1. 要开发pc端 + 移动端 + app混合开发的 页面,每个页面都是单页应用
60 | 2. 为了节约开发成本,这几个端要共用一些组件,和 方法
61 | 3. 打包要方便,调试要方便
62 | 4. vue应用
63 |
64 | #### 几个问题:
65 | 1. vue-cli提供了非常好的开发环境,我能否在这个基础上整一整,解决掉需求 2 和 3 呢?
66 | 2. vue + vuex + vue-resuorce +vue-route 的工程目录应该怎么设计呢?
67 |
68 | > 面对这样的需求,我的理解是把多个单页应用融合到一个工程里面,下面是我的解决办法
69 |
70 | #### 这个工程是啥
71 |
72 | > github [https://github.com/vincentmrlau/vue-multi-device-single-page](https://github.com/vincentmrlau/vue-multi-device-single-page),欢迎交流
73 | >
74 | > 多端(也可以是多页)的单页应用的vue工程的开发环境,本质上是多个单页应用
75 | >
76 | > 基于vue,整合了vuex vue-resuorece vue-router 的开发目录设计
77 | >
78 | > 整个基于vue-cli生成的目录进行修改,除了test(正在研究)外的功能均可使用
79 |
80 | ## 三、开发思路
81 |
82 | 1、设置公用组件的目录
83 |
84 | 2、抽离api,分为公用的api和属于各个页面自己的api
85 |
86 | 3、每个单页应用vuex管理状态
87 |
88 | 4、可能会被多人同时编辑,如何尽量减少merge
89 |
90 | 5、针对这样的需求的src下面的目录应该怎么设计(第三部分有写)
91 |
92 | 6、针对需求配置开发环境(从第 部门开始是关于这个开发环境的)
93 |
94 | ## 四、src目录设计及思路
95 | > 介绍src的目录设置及其作用
96 | >
97 | > 介绍 界面-模板html-组件-store-接口 的关系
98 |
99 | #### 概况两图流
100 | 1. pc主页示意图
101 |
102 | 
103 |
104 | 2. 分析图(怎一个乱字了得)
105 |
106 | 
107 |
108 |
109 | #### 目录设置及其作用
110 | ```
111 | ├─src # 源文件目录
112 | │ │ config.js
113 | │ │
114 | │ ├─api # 多端共用的 api
115 | │ │ device-root.js
116 | │ │ middleware.js
117 | │ │
118 | │ ├─assets # 多端共用的 资源
119 | │ │ logo.png
120 | │ │
121 | │ ├─components # 多端共用的 组件
122 | │ │ RootCommonComponent.vue
123 | │ │
124 | │ └─device # 设备入口
125 | │ ├─app # 混合开发的放这里了,也可以分 ios 和 安卓
126 | │ │ index.html # app专用的html模板,打包好的东西会自动注入
127 | │ │ index.js # app的入口文件
128 | │ │
129 | │ ├─mobile # 这里放移动端的页面 ,下面的 index文件作用类似其他端
130 | │ │ index.html
131 | │ │ index.js
132 | │ │
133 | │ └─pc # 这个目录下的都是pc端使用的,当然其他端要用也是可以的,哈哈
134 | │ │ App.vue # 入口组件
135 | │ │ index.html # 模板文件
136 | │ │ index.js # 入口文件
137 | │ │
138 | │ ├─api # 分离开接口
139 | │ │ home.js # home这个模块用的接口
140 | │ │ middleware.js # 一些公用的中间件
141 | │ │
142 | │ ├─assets # 资源
143 | │ ├─components # 组件
144 | │ │ ├─commonComponents # 公共组件
145 | │ │ │ Header.vue
146 | │ │ │
147 | │ │ ├─Home # home这个模块用的组件
148 | │ │ │ Body.vue
149 | │ │ │ Index.vue
150 | │ │ │
151 | │ │ └─Page404 # 404这个模块用的组件
152 | │ │ Index.vue
153 | │ │
154 | │ ├─router # 路由
155 | │ │ index.js
156 | │ │
157 | │ ├─store # vuex 的store
158 | │ │ │ index.js # 根级别的store + 模块组装
159 | │ │ │
160 | │ │ └─modules # store 模块
161 | │ │ home.js # home这个模块使用的store
162 | │ │
163 | │ └─types # 放类型名称
164 | │ home.js # home这个模块使用的 types
165 | │ root.js # 公用的types
166 | ```
167 |
168 | #### 界面-模板-组件 的关系
169 | > 界面:最后展现在用户面前的
170 | >
171 | > 模板:用来注入打包的html文件
172 | >
173 | > 组件:编写的vue组件
174 |
175 | 他们的关系如图:
176 |
177 | 
178 |
179 | #### 组件-store(vuex)-api(vue-resuorce) 的关系
180 | 1. 组件使用store:
181 | 1. 通过辅助函数(mapGetters,mapActions等)把store的属性映射到组件中使用
182 | 2. 组件通过action来提交mutation修改状态
183 | 3. 也可以通过$store来使用
184 | 2. 组件使用api:
185 | 1. 组件通过store的action使用api
186 | 3. store内部安排
187 | 1. 由mutation来修改状态
188 | 2. 由action来提交mutation
189 | 4. 由store的action来调用api
190 | 5. api里面分离开中间件,按需调用
191 |
192 | 看图看图 ↓↓↓
193 |
194 | 
195 |
196 |
197 |
198 | ## 五、开发环境开发
199 | > 在vue-cli v2.8.2生产的开发环境的基础上进行修改
200 |
201 | #### 新增加:build/device-conf.js 用来出路多终端(页面)开发相关问题
202 |
203 | ```
204 |
205 | var chalk = require('chalk')
206 | var glob = require('glob')
207 |
208 | // 获取deviceList
209 | var deviceList = []
210 | var deviceSrcArray = glob.sync('./src/device/*')
211 | for(var x in deviceSrcArray){
212 | deviceList.push(deviceSrcArray[x].split('/')[3])
213 | }
214 |
215 | // 检测是否在输入的参数是否在允许的list中
216 | var checkDevice = function () {
217 | var device = process.env.DEVICE_ENV
218 | var result = false
219 | // 检查deviceList是否有重复
220 | var hash = {}
221 | var repeatList = []
222 | for(var l = 0;l < deviceList.length; l++){
223 | if(hash[deviceList[l]]){
224 | repeatList.push(deviceList[l])
225 | }
226 | hash[deviceList[l]] = true
227 | }
228 | if(repeatList.length > 0){
229 | console.log(chalk.bgRed('deviceList 有重复:'))
230 | console.log(chalk.bgRed(repeatList.toString()))
231 | return result
232 | }
233 | for(var i in deviceList){
234 | if(device === deviceList[i]){
235 | result = device
236 | break
237 | }
238 | }
239 | if(result === false){
240 | console.log(chalk.bgRed('参数错误,允许的参数为:'))
241 | console.log(chalk.bgRed(deviceList.toString()))
242 | }
243 | return result
244 | }
245 |
246 | exports.deviceList = deviceList
247 | exports.checkDevice = checkDevice
248 | // 其他依赖
249 | exports.polyfills = ['babel-polyfill']
250 |
251 | ```
252 | #### 添加:/build/build-all.js
253 | > 内部根据 deviceList 产生运行build.js子进程,完成打包
254 |
255 | ```
256 | var execFileSync = require('child_process').execFileSync;
257 | var path = require('path')
258 | var deviceList = require('./device-conf').deviceList || []
259 |
260 | var buildFile = path.join(__dirname, 'build.js')
261 |
262 | for( var x in deviceList){
263 | console.log('building :',deviceList[x])
264 | execFileSync( 'node', [buildFile, deviceList[x]], {
265 |
266 | })
267 | }
268 |
269 |
270 | ```
271 |
272 | #### 修改/build/build.js
273 | > 添加设置环境变量并检查参数代码
274 |
275 | ```
276 | var chalk = require('chalk')
277 | // 设置process.env.DEVICE_ENV参数
278 | // 没有则返回错误
279 | var device = process.argv[2]
280 | var checkDevice = require('./device-conf').checkDevice
281 | if(device){
282 | process.env.DEVICE_ENV = device
283 | if(!checkDevice()){
284 | return false
285 | }
286 | }else {
287 | console.log(chalk.bgRed(' 错误:缺少参数,详情请看readme.md '))
288 | return false
289 | }
290 | ```
291 |
292 | #### 修改/build/build.js
293 | 1. 添加一个路由(在使用中间件connect-history-api-fallback之前添加),把可调试的入口展示出来
294 |
295 | ```
296 | // 写个小路由,打开浏览器的时候可以选一个开发路径
297 | var deviceList = require('./device-conf').deviceList || []
298 | var sentHref = ''
299 | for(var x in deviceList){
300 | sentHref += '点我调试终端:'+ deviceList[x].toString() +'
'
301 | }
302 | app.get('/devDeviceList', (req, res, next) => {
303 | res.send(sentHref)
304 | })
305 | ```
306 |
307 | 2. 修改打开的默认连接
308 |
309 | ```
310 | opn(uri + '/devDeviceList')
311 | ```
312 |
313 |
314 | #### 修改/config/index.js 主要修改模板入口,打包出口等
315 |
316 | ```
317 | // see http://vuejs-templates.github.io/webpack for documentation.
318 | var path = require('path')
319 | var device = process.env.DEVICE_ENV || 'undefined'
320 |
321 |
322 | // 入口模板路径
323 | var htmlTemplate = './src/device/' + device + '/index.html'
324 |
325 | module.exports = {
326 | build: {
327 | env: require('./prod.env'),
328 | // 加入html入口
329 | htmlTemplate: htmlTemplate,
330 | index: path.resolve(__dirname, '../dist' , device , 'index.html'),
331 | assetsRoot: path.resolve(__dirname, '../dist' , device),
332 | assetsSubDirectory: 'static',
333 | // 这里的路径改成相对路径
334 | // 原来是: assetsPublicPath: '/',
335 | assetsPublicPath: '',
336 | productionSourceMap: true,
337 | // Gzip off by default as many popular static hosts such as
338 | // Surge or Netlify already gzip all static assets for you.
339 | // Before setting to `true`, make sure to:
340 | // npm install --save-dev compression-webpack-plugin
341 | productionGzip: false,
342 | productionGzipExtensions: ['js', 'css'],
343 | // Run the build command with an extra argument to
344 | // View the bundle analyzer report after build finishes:
345 | // `npm run build --report`
346 | // Set to `true` or `false` to always turn it on or off
347 | bundleAnalyzerReport: process.env.npm_config_report
348 | },
349 | dev: {
350 | env: require('./dev.env'),
351 | port: 8080,
352 | autoOpenBrowser: true,
353 | assetsSubDirectory: 'static',
354 | assetsPublicPath: '/',
355 | proxyTable: {},
356 | // CSS Sourcemaps off by default because relative paths are "buggy"
357 | // with this option, according to the CSS-Loader README
358 | // (https://github.com/webpack/css-loader#sourcemaps)
359 | // In our experience, they generally work as expected,
360 | // just be aware of this issue when enabling this option.
361 | cssSourceMap: false
362 | }
363 | }
364 | ```
365 |
366 | #### 修改 /build/webpack.dev.conf.js
367 | > 主要修改了入口配置,出口配置,以及模板文件配置
368 |
369 | ```
370 | // 获取device
371 | var device = process.env.DEVICE_ENV
372 |
373 | var utils = require('./utils')
374 | var webpack = require('webpack')
375 | var config = require('../config')
376 | var merge = require('webpack-merge')
377 | var baseWebpackConfig = require('./webpack.base.conf')
378 | var HtmlWebpackPlugin = require('html-webpack-plugin')
379 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
380 |
381 | // 设置设备相关信息引入
382 | var deviceList = require('./device-conf').deviceList
383 | // 其他依赖
384 | var extraPolyfill = require('./device-conf').polyfills || []
385 |
386 | // 设置入口
387 | var entry = {}
388 | // 设置html插件模板入口和依赖
389 | var htmlPluginConf = []
390 | for(var x in deviceList){
391 | // 设置 入口
392 | entry[deviceList[x]] = extraPolyfill.concat(
393 | ['./build/dev-client'],
394 | './src/device/' + deviceList[x] + '/index.js'
395 | )
396 | var _htmlPlugin = new HtmlWebpackPlugin({
397 | filename: deviceList[x]+'/index.html',
398 | template: './src/device/' + deviceList[x] + '/index.html',
399 | chunks: [deviceList[x]]
400 | })
401 | htmlPluginConf.push(_htmlPlugin)
402 | }
403 |
404 |
405 |
406 |
407 | // add hot-reload related code to entry chunks
408 | // 把热重载所需的代码也打包进去
409 | // Object.keys(baseWebpackConfig.entry).forEach(function (name) {
410 | // baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
411 | // })
412 |
413 | // 删除的entry和output
414 | try {
415 | delete baseWebpackConfig.entry
416 | }catch (e){
417 | console.log(e)
418 | }
419 | try{
420 | delete baseWebpackConfig.output
421 | }catch (e){
422 | console.log(e)
423 | }
424 |
425 | module.exports = merge(baseWebpackConfig, {
426 | // 设置入口
427 | entry: entry,
428 | // 设置出口
429 | output: {
430 | path: '/',
431 | filename: '[name].js',
432 | publicPath: config.dev.assetsPublicPath
433 | },
434 | module: {
435 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
436 | },
437 | // cheap-module-eval-source-map is faster for development
438 | devtool: '#cheap-module-eval-source-map',
439 | plugins: [
440 | new webpack.DefinePlugin({
441 | 'process.env': config.dev.env
442 | }),
443 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
444 | new webpack.HotModuleReplacementPlugin(),
445 | new webpack.NoEmitOnErrorsPlugin(),
446 | // https://github.com/ampedandwired/html-webpack-plugin
447 | // new HtmlWebpackPlugin({
448 | // filename: 'index.html',
449 | // template: config.dev.htmlTemplate,
450 | // inject: true
451 | // }),
452 | new FriendlyErrorsPlugin()
453 | ].concat(htmlPluginConf)
454 | })
455 |
456 | ```
457 | #### 修改 /build/webpack.prod.conf.js
458 | > 主要修改了入口配置,出口配置,以及模板文件配置
459 |
460 | ```
461 | var path = require('path')
462 | var utils = require('./utils')
463 | var webpack = require('webpack')
464 | var config = require('../config')
465 | var merge = require('webpack-merge')
466 | var baseWebpackConfig = require('./webpack.base.conf')
467 | var CopyWebpackPlugin = require('copy-webpack-plugin')
468 | var HtmlWebpackPlugin = require('html-webpack-plugin')
469 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
470 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
471 |
472 | var env = process.env.NODE_ENV === 'testing'
473 | ? require('../config/test.env')
474 | : config.build.env
475 |
476 | // 设置device相关变量
477 | var device = process.env.DEVICE_ENV
478 | //设置入口
479 | var extraPolyFill = require('./device-conf').polyfills ||[]
480 | var entry = {
481 | index: extraPolyFill.concat('./src/device/' + device + '/index.js')
482 | }
483 |
484 | console.log(config.build.htmlTemplate)
485 | var webpackConfig = merge(baseWebpackConfig, {
486 | module: {
487 | rules: utils.styleLoaders({
488 | sourceMap: config.build.productionSourceMap,
489 | extract: true
490 | })
491 | },
492 | // 写入prod的入口
493 | entry: entry,
494 | devtool: config.build.productionSourceMap ? '#source-map' : false,
495 | output: {
496 | path: config.build.assetsRoot,
497 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
498 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
499 | },
500 | plugins: [
501 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
502 | new webpack.DefinePlugin({
503 | 'process.env': env
504 | }),
505 | new webpack.optimize.UglifyJsPlugin({
506 | compress: {
507 | warnings: false
508 | },
509 | sourceMap: true
510 | }),
511 | // extract css into its own file
512 | new ExtractTextPlugin({
513 | filename: utils.assetsPath('css/[name].[contenthash].css')
514 | }),
515 | // Compress extracted CSS. We are using this plugin so that possible
516 | // duplicated CSS from different components can be deduped.
517 | new OptimizeCSSPlugin({
518 | cssProcessorOptions: {
519 | safe: true
520 | }
521 | }),
522 | // generate dist pc.html with correct asset hash for caching.
523 | // you can customize output by editing /pc.html
524 | // see https://github.com/ampedandwired/html-webpack-plugin
525 | new HtmlWebpackPlugin({
526 | filename: process.env.NODE_ENV === 'testing'
527 | ? 'index.html'
528 | : config.build.index,
529 | // template: 'index.html',
530 | template: config.build.htmlTemplate,
531 | inject: true,
532 | minify: {
533 | removeComments: true,
534 | collapseWhitespace: true,
535 | removeAttributeQuotes: true
536 | // more options:
537 | // https://github.com/kangax/html-minifier#options-quick-reference
538 | },
539 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
540 | chunksSortMode: 'dependency'
541 | }),
542 | // split vendor js into its own file
543 | new webpack.optimize.CommonsChunkPlugin({
544 | name: 'vendor',
545 | minChunks: function (module, count) {
546 | // any required modules inside node_modules are extracted to vendor
547 | return (
548 | module.resource &&
549 | /\.js$/.test(module.resource) &&
550 | module.resource.indexOf(
551 | path.join(__dirname, '../node_modules')
552 | ) === 0
553 | )
554 | }
555 | }),
556 | // extract webpack runtime and module manifest to its own file in order to
557 | // prevent vendor hash from being updated whenever app bundle is updated
558 | new webpack.optimize.CommonsChunkPlugin({
559 | name: 'manifest',
560 | chunks: ['vendor']
561 | }),
562 | // copy custom static assets
563 | new CopyWebpackPlugin([
564 | {
565 | from: path.resolve(__dirname, '../static'),
566 | to: config.build.assetsSubDirectory,
567 | ignore: ['.*']
568 | }
569 | ])
570 | ]
571 | })
572 |
573 | if (config.build.productionGzip) {
574 | var CompressionWebpackPlugin = require('compression-webpack-plugin')
575 |
576 | webpackConfig.plugins.push(
577 | new CompressionWebpackPlugin({
578 | asset: '[path].gz[query]',
579 | algorithm: 'gzip',
580 | test: new RegExp(
581 | '\\.(' +
582 | config.build.productionGzipExtensions.join('|') +
583 | ')$'
584 | ),
585 | threshold: 10240,
586 | minRatio: 0.8
587 | })
588 | )
589 | }
590 |
591 | if (config.build.bundleAnalyzerReport) {
592 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
593 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
594 | }
595 |
596 | module.exports = webpackConfig
597 |
598 | ```
599 |
600 | ## 六、整个开发环境的目录注释
601 |
602 | ```
603 | │ .babelrc
604 | │ .editorconfig
605 | │ .eslintignore
606 | │ .eslintrc.js
607 | │ .gitignore
608 | │ .postcssrc.js
609 | │ index.html
610 | │ npm-debug.log
611 | │ package.json
612 | │ README.md
613 | │ tree.txt
614 | │
615 | ├─build # 这里是打包工具相关的
616 | │ build-all.js # 通过打包所有端的代码
617 | │ build.js # 这里设定进程的环境变量
618 | │ check-versions.js
619 | │ dev-client.js
620 | │ dev-server.js # 这里也需要对进程的环境变量进行设定
621 | │ device-conf.js # 这里面有关于多端开发、打包的相关设定
622 | │ utils.js
623 | │ vue-loader.conf.js
624 | │ webpack.base.conf.js # 修改了入口、出口等
625 | │ webpack.dev.conf.js # 修改了入口、出口等
626 | │ webpack.prod.conf.js # 修改了入口出口等
627 | │ webpack.test.conf.js # 测试相关还未完善
628 | │
629 | ├─config
630 | │ dev.env.js
631 | │ index.js # 打包的入口和出口
632 | │ prod.env.js
633 | │ test.env.js
634 | │
635 | ├─dist # 最后打包的目录 分端储存
636 | │ ├─app
637 | │ │ │ index.html
638 | │ │ │
639 | │ │ └─static
640 | │ │ └─js
641 | │ │ index.0142f89e3523b3b0d16b.js
642 | │ │ index.0142f89e3523b3b0d16b.js.map
643 | │ │ manifest.57f6691c595e842abc95.js
644 | │ │ manifest.57f6691c595e842abc95.js.map
645 | │ │ vendor.cce790f63359fc27fa7d.js
646 | │ │ vendor.cce790f63359fc27fa7d.js.map
647 | │ │
648 | │ ├─mobile
649 | │ │ │ index.html
650 | │ │ │
651 | │ │ └─static
652 | │ │ └─js
653 | │ │ index.0142f89e3523b3b0d16b.js
654 | │ │ index.0142f89e3523b3b0d16b.js.map
655 | │ │ manifest.57f6691c595e842abc95.js
656 | │ │ manifest.57f6691c595e842abc95.js.map
657 | │ │ vendor.cce790f63359fc27fa7d.js
658 | │ │ vendor.cce790f63359fc27fa7d.js.map
659 | │ │
660 | │ └─pc
661 | │ │ index.html
662 | │ │
663 | │ └─static
664 | │ ├─css
665 | │ │ index.1e809171f3a961de951e3c8e6644435f.css
666 | │ │ index.1e809171f3a961de951e3c8e6644435f.css.map
667 | │ │
668 | │ └─js
669 | │ 0.f3e74a76d92b3f6ca5ec.js
670 | │ 0.f3e74a76d92b3f6ca5ec.js.map
671 | │ 1.fb471d3425df8c16ac54.js
672 | │ 1.fb471d3425df8c16ac54.js.map
673 | │ index.a2ba631673923f812cf1.js
674 | │ index.a2ba631673923f812cf1.js.map
675 | │ manifest.ab6461111db19541d04b.js
676 | │ manifest.ab6461111db19541d04b.js.map
677 | │ vendor.aeee805b1efff3748018.js
678 | │ vendor.aeee805b1efff3748018.js.map
679 | │
680 | ├─images # 这个放点文档写文档用的图片
681 | ├─sever # 这里写点服务端程序,用于测试等
682 | │ prod-view-server.js
683 | │
684 | ├─src # 源文件目录
685 | │ │ config.js
686 | │ │
687 | │ ├─api # 多端共用的 api
688 | │ │ device-root.js
689 | │ │ middleware.js
690 | │ │
691 | │ ├─assets # 多端共用的 资源
692 | │ │ logo.png
693 | │ │
694 | │ ├─components # 多端共用的 组件
695 | │ │ RootCommonComponent.vue
696 | │ │
697 | │ └─device # 设备入口
698 | │ ├─app # 混合开发的放这里了,也可以分 ios 和 安卓
699 | │ │ index.html # app专用的html模板,打包好的东西会自动注入
700 | │ │ index.js # app的入口文件
701 | │ │
702 | │ ├─mobile # 这里放移动端的页面 ,下面的 index文件作用类似其他端
703 | │ │ index.html
704 | │ │ index.js
705 | │ │
706 | │ └─pc # 这个目录下的都是pc端使用的,当然其他端要用也是可以的,哈哈
707 | │ │ App.vue # 入口组件
708 | │ │ index.html # 模板文件
709 | │ │ index.js # 入口文件
710 | │ │
711 | │ ├─api # 分离开接口
712 | │ │ home.js # home这个模块用的接口
713 | │ │ middleware.js # 一些公用的中间件
714 | │ │
715 | │ ├─assets # 资源
716 | │ ├─components # 组件
717 | │ │ ├─commonComponents # 公共组件
718 | │ │ │ Header.vue
719 | │ │ │
720 | │ │ ├─Home # home这个模块用的组件
721 | │ │ │ Body.vue
722 | │ │ │ Index.vue
723 | │ │ │
724 | │ │ └─Page404 # 404这个模块用的组件
725 | │ │ Index.vue
726 | │ │
727 | │ ├─router # 路由
728 | │ │ index.js
729 | │ │
730 | │ ├─store # vuex 的store
731 | │ │ │ index.js # 根级别的store + 模块组装
732 | │ │ │
733 | │ │ └─modules # store 模块
734 | │ │ home.js # home这个模块使用的store
735 | │ │
736 | │ └─types # 放类型名称
737 | │ home.js # home这个模块使用的 types
738 | │ root.js # 公用的types
739 | │
740 | ├─static
741 | │ .gitkeep
742 | │
743 | └─test # 测试相关 TODO
744 |
745 | ```
746 |
747 |
748 |
749 |
--------------------------------------------------------------------------------