[
  {
    "path": ".browserslistrc",
    "content": "> 1%\nlast 2 versions\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 4\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".eslintignore",
    "content": "build/*.js\nconfig/*.js\npublic/static/**/*.js\ndist/**/*.js\ndist/**/*.css\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n    \"extends\": [\"lcy-vue\"],\n    \"rules\": {\n        \"no-irregular-whitespace\": 0\n    }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.idea/\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\n*-port.txt\n\npackage-lock.json\nadmin.lock\nyarn-error.log\nserver/config/secret.js\nserver/config/mpapp.js\nserver/config/shihua.js\n"
  },
  {
    "path": ".prettierignore",
    "content": "package.json\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n    \"printWidth\": 150,\n    \"semi\": false,\n    \"tabWidth\": 4,\n    \"singleQuote\": true,\n    \"trailingComma\": \"none\",\n    \"arrowParens\": \"avoid\",\n    \"htmlWhitespaceSensitivity\": \"css\"\n}\n"
  },
  {
    "path": "README.md",
    "content": "# vue2 多页配置实例\n\n基于`vue2 + vue-router + vuex`而组成的多页配置实例\n\n多页实例中包含 纯单页, 基于 vue-router 的单页, 基于 vue-router + vuex 的单页, 多种模式自由组合\n\n在 module 文件夹中只留一个模块, 就变成 纯`SPA`\n\n所有模块均带修改head里的title, 所有模块也都包含`ajax`例子, 任何不带`ajax`的例子都是耍流氓\n\nvuex模块带有懒加载\n\nDEMO: http://old.mmxiaowu.com/vue2-multiple-entry/index\n\nfork demo\n\n```bash\n$ git clone\n\n// 安装依赖\n$ yarn\n\n// 生产模式\n$ yarn build\n\n// 开发模式\n$ yarn serve\n\n// eslint 检测\n$ yarn lint\n```\n\n访问: http://localhost:8086/index\n\n\n# 目录结构\n- /dist/           = webpack编译后生成文件目录\n- /src/api/        = axios配置目录\n- /src/assets/     = 静态文件目录\n- /src/components/ = 组件目录\n- /src/modules/    = 多页面模块, 每个模块一个文件夹\n- /src/modules/router    = 多页面模块之带路由模块的例子\n- /src/modules/vuex    = 多页面模块之带路由和vuex的模块的例子\n- /utils/          = 一些有用的插件\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n    presets: ['@vue/app']\n}\n"
  },
  {
    "path": "entris.js",
    "content": "const fs = require('fs')\nconst path = require('path')\nconst entryPath = path.resolve(__dirname, './src/modules')\n\nconst entris = fs.readdirSync(entryPath).reduce(function (o, dirname) {\n    o[dirname] = path.join(entryPath, dirname)\n    return o\n}, {})\n\nmodule.exports = entris\n"
  },
  {
    "path": "jsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"baseUrl\": \".\",\n        \"paths\": {\n            \"@/*\": [\"src/*\"]\n        },\n        \"target\": \"ES6\",\n        \"module\": \"commonjs\",\n        \"allowSyntheticDefaultImports\": true\n    },\n    \"include\": [\"src/**/*\"],\n    \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"vue2-multiple-entry\",\n  \"version\": \"2.0.2\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"vue-cli-service lint\"\n  },\n  \"dependencies\": {\n    \"axios\": \"^0.21.1\",\n    \"core-js\": \"^3.8.3\",\n    \"nprogress\": \"^0.2.0\",\n    \"store2\": \"^2.12.0\",\n    \"toastr\": \"^2.1.4\",\n    \"vue\": \"^2.6.12\",\n    \"vue-meta\": \"^2.4.0\",\n    \"vue-router\": \"^3.5.1\",\n    \"vueg\": \"^1.4.5\",\n    \"vuex\": \"^3.6.2\",\n    \"vuex-router-sync\": \"^5.0.0\"\n  },\n  \"devDependencies\": {\n    \"@vue/cli-plugin-babel\": \"^4.5.11\",\n    \"@vue/cli-plugin-eslint\": \"^4.5.11\",\n    \"@vue/cli-service\": \"^4.5.11\",\n    \"@vue/eslint-config-prettier\": \"^6.0.0\",\n    \"babel-eslint\": \"^10.1.0\",\n    \"caniuse-lite\": \"^1.0.30001183\",\n    \"eslint\": \"^7.19.0\",\n    \"eslint-config-lcy-vue\": \"^3.1.1\",\n    \"eslint-plugin-babel\": \"^5.3.1\",\n    \"eslint-plugin-import\": \"^2.22.1\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"eslint-plugin-vue\": \"^7.5.0\",\n    \"lint-staged\": \"^10.5.3\",\n    \"node-sass\": \"^5.0.0\",\n    \"prettier\": \"^2.2.1\",\n    \"sass-loader\": \"^10.1.1\",\n    \"vue-template-compiler\": \"^2.6.12\"\n  },\n  \"gitHooks\": {\n    \"pre-commit\": \"lint-staged\"\n  },\n  \"lint-staged\": {\n    \"*.{js,vue}\": [\n      \"vue-cli-service lint\"\n    ]\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n    plugins: {\n        autoprefixer: {}\n    }\n}\n"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title>vue2-multiple-entry</title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but vue2-multiple-entry doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "public/robots.txt",
    "content": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "public/static/manifest.json",
    "content": "{\n  \"name\": \"vue2-multiple-entry\",\n  \"short_name\": \"vue2-multiple-entry\",\n  \"icons\": [\n    {\n      \"src\": \"/static/img/icons/android-chrome-48x48.png\",\n      \"sizes\": \"48x48\",\n      \"type\": \"image/png\"\n    }, {\n      \"src\": \"/static/img/icons/android-chrome-72x72.png\",\n      \"sizes\": \"72x72\",\n      \"type\": \"image/png\"\n    }, {\n      \"src\": \"/static/img/icons/android-chrome-96x96.png\",\n      \"sizes\": \"96x96\",\n      \"type\": \"image/png\"\n    }, {\n      \"src\": \"/static/img/icons/msapplication-icon-144x144.png\",\n      \"sizes\": \"144x144\",\n      \"type\": \"image/png\"\n    }, {\n      \"src\": \"/static/img/icons/android-chrome-168x168.png\",\n      \"sizes\": \"168x168\",\n      \"type\": \"image/png\"\n    }, {\n      \"src\": \"/static/img/icons/android-chrome-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\"\n    }, {\n      \"src\": \"/static/img/icons/android-chrome-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\"\n    }\n  ],\n  \"start_url\": \"/\",\n  \"background_color\": \"#000000\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#2874f0\"\n}\n"
  },
  {
    "path": "src/api/config.js",
    "content": "module.exports = {\n    api: 'https://cnodejs.org/api/v1/',\n    timeout: 30000\n}\n"
  },
  {
    "path": "src/api/index.js",
    "content": "import config from '@/api/config'\nimport { setMessage } from '@/utils'\nimport axios from 'axios'\nimport NProgress from 'nprogress'\nimport qs from 'qs'\n\naxios.interceptors.request.use(\n    config => {\n        NProgress.start()\n        return config\n    },\n    error => Promise.reject(error)\n)\n\naxios.interceptors.response.use(\n    response => response,\n    error => Promise.resolve(error.response)\n)\n\nfunction checkStatus(response) {\n    NProgress.done()\n    if (response.status === 200 || response.status === 304) {\n        return response.data\n    }\n    return {\n        success: false,\n        message: response.statusText,\n        data: response.statusText\n    }\n}\n\nfunction checkCode(res) {\n    if (!res.success) {\n        setMessage(res.message || res.data)\n    }\n    return res\n}\n\nexport default {\n    post(url, data) {\n        return axios({\n            method: 'post',\n            url: config.api + url,\n            data: qs.stringify(data),\n            timeout: config.timeout,\n            headers: {\n                'X-Requested-With': 'XMLHttpRequest',\n                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'\n            }\n        })\n            .then(checkStatus)\n            .then(checkCode)\n    },\n    get(url, params) {\n        return axios({\n            method: 'get',\n            url: config.api + url,\n            params,\n            timeout: config.timeout,\n            headers: {\n                'X-Requested-With': 'XMLHttpRequest'\n            }\n        })\n            .then(checkStatus)\n            .then(checkCode)\n    }\n}\n"
  },
  {
    "path": "src/assets/scss/_reset.scss",
    "content": "html {\n    overflow-x: hidden;\n    overflow-y: scroll;\n    background: #ebf0f0;\n    overflow-anchor: none;\n}\n/* 清除内外边距 */\n\nbody, h1, h2, h3, h4, h5, h6, hr, p, blockquote,\n/* structural elements 结构元素 */\n\ndl, dt, dd, ul, ol, li,\n/* list elements 列表元素 */\n\npre,\n/* text formatting elements 文本格式元素 */\n\nfieldset, button, input, textarea, th, td {\n    margin: 0;\n    padding: 0;\n}\n\n\n/* 设置默认字体 */\n\nbody, button, input, select, textarea {\n    color: #333;\n    outline: none;\n\tfont-family: -apple-system-font, \"Helvetica Neue\", Tahoma, \"PingFang SC\", \"lantinghei sc\", \"Microsoft Yahei\", sans-serif;\n\tfont-size: 16px;\n\tline-height: 1.6;\n\tfont-feature-settings: 'kern' 1;\n\t-webkit-font-smoothing: antialiased;\n}\n\nh1 {\n    font-size: 20px;\n    /* 18px / 12px = 1.5 */\n}\n\nh2 {\n    font-size: 18px;\n}\n\nh3 {\n    font-size: 16px;\n}\n\nh4, h5, h6 {\n    font-size: 100%;\n}\n\naddress, cite, dfn, em, var {\n    font-style: normal;\n}\n\n\n/* 统一等宽字体 */\n\nsmall {\n    font-size: 12px;\n}\n\n\n/* 小于 12px 的中文很难阅读，让 small 正常化 */\n\n\n/* 重置列表元素 */\n\nul, ol {\n    list-style: none;\n}\n\n\n/* 重置文本格式元素 */\n\na {\n    text-decoration: none;\n    -webkit-tap-highlight-color: rgba(255, 255, 255, 0);\n}\n\na:hover {\n    text-decoration: none;\n}\n\nabbr[title], acronym[title] {\n    /* 注：1.ie6 不支持 abbr; 2.这里用了属性选择符，ie6 下无效果 */\n    border-bottom: 1px dotted;\n    cursor: help;\n}\n\nq:before, q:after {\n    content: '';\n}\n\n\n/* 重置表单元素 */\n\nlegend {\n    color: #000;\n}\n\n\n/* for ie6 */\n\nfieldset, img {\n    border: none;\n}\n\n/* 注：optgroup 无法扶正 */\n\nbutton, input, select, textarea {\n    font-size: 100%;\n    /* 使得表单元素在 ie 下能继承字体大小 */\n}\n\n\n/* 重置表格元素 */\n\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}\n\n\n/* 重置 hr */\n\nhr {\n    border: none;\n    height: 1px;\n}\n\narticle, aside, canvas, figure, figure img, figcaption, hgroup, footer, header, nav, section, audio, video {\n    position: relative;\n    display: block;\n}\n\nnav ul, nav ol {\n    list-style: none;\n}\n\n.hidden {\n    display: none;\n}\n\n.clearfix {\n    *zoom: 1;\n}\n\n.clearfix:before, .clearfix:after {\n    display: table;\n    content: \"\";\n}\n\n.clearfix:after {\n    clear: both;\n}\n"
  },
  {
    "path": "src/assets/scss/style.scss",
    "content": "@import '_reset.scss';\n\n#vueg-background {\n    padding-top: 80px;\n    box-sizing: border-box;\n    background: none !important;\n}\n.g-doc {\n    display: flex;\n    flex-direction: column;\n    min-height: 100vh;\n}\n.nav-wrap {\n    flex: 0 0 60px;\n    margin-bottom: 20px;\n    background: #54d9e0;\n    .nav-block {\n        display: flex;\n        align-items: center;\n        width: 1200px;\n        height: 60px;\n        margin: 0 auto;\n        li {\n            flex: 0 0 auto;\n            list-style: none;\n            width: 120px;\n            text-align: center;\n            a {\n                font-size: 16px;\n                color: #fff;\n            }\n            &.current {\n                a {\n                    color: red;\n                }\n            }\n            &.logo {\n                width: 109px;\n                margin-right: 30px;\n                img {\n                    width: 109px;\n                    height: 31px;\n                }\n            }\n        }\n    }\n}\n.body {\n    flex: 1 1 auto;\n    width: 1200px;\n    margin: 0 auto 20px;\n    padding: 20px;\n    background: #fff;\n    border-radius: 5px;\n    box-shadow: 0 0 10px #eee;\n    .header {\n        position: relative;\n        padding-bottom: 15px;\n        text-align: center;\n        font-size: 16px;\n        font-weight: 800;\n        border-bottom: 1px solid #eee;\n        a {\n            display: inline-block;\n            position: absolute;\n            right: 0;\n            top: 0;\n            font-weight: 400;\n            font-size: 14px;\n            line-height: 22px;\n        }\n    }\n    .topics {\n        margin-top: 20px;\n        li + li {\n            margin-top: 10px;\n        }\n    }\n    .content {\n        margin-top: 20px;\n        .markdown-text {\n            word-break: break-all;\n        }\n        img {\n            max-width: 100%;\n        }\n    }\n    .pages {\n        margin-top: 20px;\n        padding-top: 20px;\n        text-align: center;\n        border-top: 1px solid #eee;\n        a {\n            display: inline-block;\n            & + a {\n                margin-left: 20px;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/components/module-1.vue",
    "content": "<template>\n    <div class=\"body\">\n        <div class=\"header\">这是首页模块</div>\n        <ul class=\"topics\">\n            <li v-for=\"item in topics\" :key=\"item.id\"><a :href=\"`./view?id=${item.id}`\" v-text=\"item.title\" target=\"_blank\"></a></li>\n        </ul>\n        <div class=\"pages\">\n            <a v-if=\"page > 1\" :href=\"`?page=${page - 1}`\">上一页</a> <a v-else href=\"javascript:;\">上一页</a>\n            <a :href=\"`?page=${page + 1}`\">下一页</a>\n        </div>\n    </div>\n</template>\n<script>\nexport default {\n    props: {\n        topics: {\n            type: Array,\n            default: () => []\n        },\n        page: {\n            default: 1\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/components/module-2.vue",
    "content": "<template>\n    <div class=\"body\">\n        <div class=\"header\">这是模块 - 2</div>\n        <ul class=\"topics\">\n            <li v-for=\"item in topics\" :key=\"item.id\"><a :href=\"`./view?id=${item.id}`\" v-text=\"item.title\" target=\"_blank\"></a></li>\n        </ul>\n        <div class=\"pages\">\n            <a v-if=\"page > 1\" :href=\"`?page=${page - 1}`\">上一页</a> <a v-else href=\"javascript:;\">上一页</a>\n            <a :href=\"`?page=${page + 1}`\">下一页</a>\n        </div>\n    </div>\n</template>\n<script>\nexport default {\n    props: {\n        topics: {\n            type: Array,\n            default: () => []\n        },\n        page: {\n            default: 1\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/components/module-3.vue",
    "content": "<template>\n    <div class=\"body\">\n        <div class=\"header\">这是模块 - 3</div>\n        <ul class=\"topics\">\n            <li v-for=\"item in topics\" :key=\"item.id\"><a :href=\"`./view?id=${item.id}`\" v-text=\"item.title\" target=\"_blank\"></a></li>\n        </ul>\n        <div class=\"pages\">\n            <a v-if=\"page > 1\" :href=\"`?page=${page - 1}`\">上一页</a> <a v-else href=\"javascript:;\">上一页</a>\n            <a :href=\"`?page=${page + 1}`\">下一页</a>\n        </div>\n    </div>\n</template>\n<script>\nexport default {\n    props: {\n        topics: {\n            type: Array,\n            default: () => []\n        },\n        page: {\n            default: 1\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/components/module-view.vue",
    "content": "<template>\n    <div class=\"body\">\n        <div class=\"header\">{{ data.title }}</div>\n        <div class=\"content\" v-html=\"data.content\"></div>\n    </div>\n</template>\n<script>\nexport default {\n    props: ['data']\n}\n</script>\n"
  },
  {
    "path": "src/components/nav-component.vue",
    "content": "<template>\n    <div class=\"nav-wrap\">\n        <ul class=\"nav-block\">\n            <li class=\"logo\"><img src=\"http://img.daliangju.com/upload/20180603/1528019409246zkdt80.png\" alt=\"\" /></li>\n            <li :class=\"{ current: current === 1 }\">\n                <a href=\"./index\"><i></i>首页</a>\n            </li>\n            <li :class=\"{ current: current === 2 }\">\n                <a href=\"./module2\"><i></i>模块2</a>\n            </li>\n            <li :class=\"{ current: current === 3 }\">\n                <a href=\"./module3\"><i></i>模块3</a>\n            </li>\n            <li :class=\"{ current: current === 4 }\">\n                <a href=\"./router\"><i></i>路由</a>\n            </li>\n            <li :class=\"{ current: current === 5 }\">\n                <a href=\"./vuex\"><i></i>Vuex</a>\n            </li>\n        </ul>\n    </div>\n</template>\n<script>\nimport '../assets/scss/style.scss'\nexport default {\n    props: ['current']\n}\n</script>\n"
  },
  {
    "path": "src/modules/index/app.vue",
    "content": "<template>\n    <div class=\"g-doc\">\n        <nav-component :current=\"1\" />\n        <modules :topics=\"topics\" :page=\"page\" />\n    </div>\n</template>\n<script>\nimport navComponent from '@/components/nav-component.vue'\nimport modules from '@/components/module-1.vue'\nimport api from '@/api'\nexport default {\n    name: 'index-app',\n    components: {\n        navComponent,\n        modules\n    },\n    data() {\n        return {\n            page: Number(new URLSearchParams(window.location.search).get('page')) || 1,\n            topics: []\n        }\n    },\n    async mounted() {\n        const { success, data } = await api.get('topics', { page: this.page })\n        if (success) this.topics = data\n    },\n    metaInfo: {\n        title: '首页'\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/index/index.js",
    "content": "import '@/polyfill'\n\nimport Vue from 'vue'\nimport Meta from 'vue-meta'\nimport App from './app.vue'\n\nVue.use(Meta)\n\nconst app = new Vue({\n    ...App\n})\n\napp.$mount('#app')\n"
  },
  {
    "path": "src/modules/module2/app.vue",
    "content": "<template>\n    <div class=\"g-doc\">\n        <nav-component :current=\"2\" />\n        <modules :topics=\"topics\" :page=\"page\" />\n    </div>\n</template>\n<script>\nimport navComponent from '@/components/nav-component.vue'\nimport modules from '@/components/module-2.vue'\nimport api from '@/api'\nexport default {\n    name: 'index-app',\n    components: {\n        navComponent,\n        modules\n    },\n    data() {\n        return {\n            page: Number(new URLSearchParams(window.location.search).get('page')) || 1,\n            topics: []\n        }\n    },\n    async mounted() {\n        const { success, data } = await api.get('topics', { page: this.page })\n        if (success) this.topics = data\n    },\n    metaInfo: {\n        title: '模块2'\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/module2/index.js",
    "content": "import '@/polyfill'\n\nimport Vue from 'vue'\nimport Meta from 'vue-meta'\nimport App from './app.vue'\n\nVue.use(Meta)\n\nconst app = new Vue({\n    ...App\n})\n\napp.$mount('#app')\n"
  },
  {
    "path": "src/modules/module3/app.vue",
    "content": "<template>\n    <div class=\"g-doc\">\n        <nav-component :current=\"3\" />\n        <modules :topics=\"topics\" :page=\"page\" />\n    </div>\n</template>\n<script>\nimport navComponent from '@/components/nav-component.vue'\nimport modules from '@/components/module-3.vue'\nimport api from '@/api'\nexport default {\n    name: 'index-app',\n    components: {\n        navComponent,\n        modules\n    },\n    data() {\n        return {\n            page: Number(new URLSearchParams(window.location.search).get('page')) || 1,\n            topics: []\n        }\n    },\n    async mounted() {\n        const { success, data } = await api.get('topics', { page: this.page })\n        if (success) this.topics = data\n    },\n    metaInfo: {\n        title: '模块3'\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/module3/index.js",
    "content": "import '@/polyfill'\n\nimport Vue from 'vue'\nimport Meta from 'vue-meta'\nimport App from './app.vue'\n\nVue.use(Meta)\n\nconst app = new Vue({\n    ...App\n})\n\napp.$mount('#app')\n"
  },
  {
    "path": "src/modules/router/app.vue",
    "content": "<template>\n    <div class=\"g-doc\">\n        <nav-component :current=\"4\" />\n        <keep-alive :include=\"cachedViews\">\n            <router-view :key=\"key\" class=\"body\"></router-view>\n        </keep-alive>\n        <!-- <router-view :key=\"key\" class=\"body\" v-transition></router-view> -->\n    </div>\n</template>\n<script>\nimport navComponent from '@/components/nav-component.vue'\n\nimport 'nprogress/nprogress.css'\nimport 'toastr/build/toastr.min.css'\n\nexport default {\n    name: 'router-app',\n    components: {\n        navComponent\n    },\n    data() {\n        return {\n            cachedViews: ['router-index']\n        }\n    },\n    computed: {\n        key() {\n            return this.$route.path.replace(/\\//g, '_')\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/router/components/lists.vue",
    "content": "<template>\n    <div>\n        <div class=\"header\">这是带路由的模块</div>\n        <ul class=\"topics\">\n            <li v-for=\"item in topics\" :key=\"item.id\"><router-link :to=\"`/view/${item.id}`\" v-text=\"item.title\"></router-link></li>\n        </ul>\n        <div v-if=\"loading\" class=\"pages\">\n            <a href=\"javascript:;\">加载中...</a>\n        </div>\n        <div v-else class=\"pages\">\n            <a @click=\"$emit('get-data', page + 1)\" href=\"javascript:;\">加载更多</a>\n        </div>\n    </div>\n</template>\n<script>\nexport default {\n    props: ['topics', 'page', 'loading']\n}\n</script>\n"
  },
  {
    "path": "src/modules/router/components/view.vue",
    "content": "<template>\n    <div>\n        <div class=\"header\">\n            {{ data.title }}\n            <router-link to=\"/\">返回列表</router-link>\n        </div>\n        <div class=\"content\" v-html=\"data.content\"></div>\n    </div>\n</template>\n<script>\nexport default {\n    props: ['data']\n}\n</script>\n"
  },
  {
    "path": "src/modules/router/index.js",
    "content": "import '@/polyfill'\n\nimport Vue from 'vue'\nimport Meta from 'vue-meta'\n// import vueg from 'vueg'\nimport router from './router'\nimport App from './app.vue'\n\nVue.use(Meta)\n// Vue.use(vueg, router, {\n//     shadow: false,\n//     forwardAnim: 'fadeInRight'\n// })\n\nconst app = new Vue({\n    router,\n    ...App\n})\n\napp.$mount('#app')\n"
  },
  {
    "path": "src/modules/router/pages/index.vue",
    "content": "<template>\n    <modules :topics=\"topics\" @get-data=\"getData\" :page=\"page\" :loading=\"loading\" />\n</template>\n<script>\nimport ls from 'store2'\nimport api from '@/api'\n\nimport modules from '../components/lists.vue'\n\nexport default {\n    name: 'router-index',\n    components: {\n        modules\n    },\n    data() {\n        return {\n            topics: [],\n            page: 1,\n            loading: false\n        }\n    },\n    async mounted() {\n        this.getData()\n    },\n    activated() {\n        console.log(`activated`)\n        const path = this.$route.path\n        const scrollTop = ls.get(path) || 0\n        ls.remove(path)\n        if (scrollTop) window.scrollTo(0, scrollTop)\n    },\n    methods: {\n        async getData(page = 1) {\n            if (page > 1) this.loading = true\n            const { success, data } = await api.get('topics', { page })\n            this.loading = false\n            if (success) {\n                this.page = page\n                this.topics = this.topics.concat(data)\n            }\n        }\n    },\n    beforeRouteLeave(to, from, next) {\n        const scrollTop = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop)\n        const path = from.path\n        if (scrollTop) ls.set(path, scrollTop)\n        else ls.remove(path)\n        next()\n    },\n    metaInfo: {\n        title: '这个是带路由的模块'\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/router/pages/view.vue",
    "content": "<template>\n    <views :data=\"item\" />\n</template>\n<script>\nimport api from '@/api'\nimport views from '../components/view.vue'\n\nexport default {\n    components: {\n        views\n    },\n    data() {\n        return {\n            item: {}\n        }\n    },\n    async mounted() {\n        const id = this.$route.params.id\n        const { success, data } = await api.get(`topic/${id}`)\n        if (success) this.item = data\n    },\n    metaInfo() {\n        return {\n            title: (this.item && this.item.title) || ''\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/router/router/index.js",
    "content": "/* eslint-disable no-inline-comments */\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\n// 正常打包\n// import index from '../pages/index.vue'\n// import view from '../pages/view.vue'\n// 懒加载\n// const index = resolve => require(['../pages/index.vue'], resolve)\n// const view = resolve => require(['../pages/view.vue'], resolve)\n// 懒加载 - 按组\n// const index = r => require.ensure([], () => r(require('../pages/index.vue')), 'group-index')\n// const view = r => require.ensure([], () => r(require('../pages/view.vue')), 'group-view')\n// 懒加载 - 按组 import\nconst index = () => import(/* webpackChunkName: \"router-index\" */ '../pages/index.vue')\nconst view = () => import(/* webpackChunkName: \"router-view\" */ '../pages/view.vue')\n\nVue.use(VueRouter)\n\nconst router = new VueRouter({\n    mode: 'hash',\n    //base: __dirname,\n    routes: [\n        { name: 'index', path: '/', component: index },\n        { name: 'view', path: '/view/:id', component: view }\n    ]\n})\n\nexport default router\n"
  },
  {
    "path": "src/modules/view/app.vue",
    "content": "<template>\n    <div class=\"g-doc\">\n        <nav-component />\n        <views :data=\"data\" />\n    </div>\n</template>\n<script>\nimport navComponent from '@/components/nav-component.vue'\nimport views from '@/components/module-view.vue'\nimport api from '@/api'\nexport default {\n    components: {\n        navComponent,\n        views\n    },\n    data() {\n        return {\n            data: {}\n        }\n    },\n    async mounted() {\n        const id = new URLSearchParams(window.location.search).get('id')\n        const { success, data } = await api.get(`topic/${id}`)\n        if (success) this.data = data\n    },\n    metaInfo() {\n        const title = this.data.title ? this.data.title : ''\n        return {\n            title\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/view/index.js",
    "content": "import '@/polyfill'\n\nimport Vue from 'vue'\nimport Meta from 'vue-meta'\nimport App from './app.vue'\n\nVue.use(Meta)\n\nconst app = new Vue({\n    ...App\n})\n\napp.$mount('#app')\n"
  },
  {
    "path": "src/modules/vuex/app.vue",
    "content": "<template>\n    <div class=\"g-doc\">\n        <nav-component :current=\"5\" />\n        <router-view :key=\"key\" class=\"body\"></router-view>\n        <!-- <router-view :key=\"key\" class=\"body\" v-transition></router-view> -->\n    </div>\n</template>\n<script>\nimport navComponent from '@/components/nav-component.vue'\n\nimport 'nprogress/nprogress.css'\nimport 'toastr/build/toastr.min.css'\n\nexport default {\n    name: 'vuex-app',\n    components: {\n        navComponent\n    },\n    computed: {\n        key() {\n            return this.$route.path.replace(/\\//g, '_')\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/vuex/components/lists.vue",
    "content": "<template>\n    <div>\n        <ul class=\"topics\">\n            <li v-for=\"item in topics\" :key=\"item.id\"><router-link :to=\"`/view/${item.id}`\" v-text=\"item.title\"></router-link></li>\n        </ul>\n        <div class=\"pages\">\n            <a v-if=\"loading\" href=\"javascript:;\">加载中...</a> <a v-else @click=\"$emit('loadMore')\" href=\"javascript:;\">加载更多...</a>\n        </div>\n    </div>\n</template>\n<script>\nexport default {\n    props: ['topics', 'loading']\n}\n</script>\n"
  },
  {
    "path": "src/modules/vuex/components/view.vue",
    "content": "<template>\n    <div>\n        <div class=\"header\">\n            {{ data.title }}\n            <router-link to=\"/\">返回列表</router-link>\n        </div>\n        <div class=\"content\" v-html=\"data.content\"></div>\n    </div>\n</template>\n<script>\nexport default {\n    props: ['data']\n}\n</script>\n"
  },
  {
    "path": "src/modules/vuex/index.js",
    "content": "import '@/polyfill'\n\nimport Vue from 'vue'\nimport Meta from 'vue-meta'\n// import vueg from 'vueg'\nimport store from './store'\nimport router from './router'\nimport { sync } from 'vuex-router-sync'\nimport App from './app.vue'\n\nVue.use(Meta)\n// Vue.use(vueg, router, {\n//     // duration: '10',\n//     shadow: false,\n//     forwardAnim: 'fadeInRight'\n// })\n\nsync(store, router)\n\nrouter.beforeEach((route, redirect, next) => {\n    window.scrollTo(0, 0)\n    next()\n})\n\nconst app = new Vue({\n    router,\n    store,\n    ...App\n})\n\napp.$mount('#app')\n"
  },
  {
    "path": "src/modules/vuex/pages/index.vue",
    "content": "<template>\n    <modules @loadMore=\"loadMore\" :loading=\"loading\" :topics=\"topics.data\" />\n</template>\n<script>\nimport { mapGetters } from 'vuex'\nimport ls from 'store2'\n\nimport modules from '../components/lists.vue'\n\nexport default {\n    name: 'vuex-index',\n    components: {\n        modules\n    },\n    data() {\n        return {\n            loading: false\n        }\n    },\n    computed: {\n        ...mapGetters({\n            topics: 'topics/getTopics'\n        })\n    },\n    async mounted() {\n        await this.$store.dispatch('topics/getTopics', { page: 1 })\n        await this.$nextTick()\n        const path = this.$route.path\n        const scrollTop = ls.get(path) || 0\n        ls.remove(path)\n        window.scrollTo(0, scrollTop)\n    },\n    methods: {\n        async loadMore() {\n            this.loading = true\n            const page = this.topics.page + 1\n            await this.$store.dispatch('topics/getTopics', { page })\n            this.loading = false\n        }\n    },\n    beforeRouteLeave(to, from, next) {\n        const scrollTop = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop)\n        const path = from.path\n        if (scrollTop) ls.set(path, scrollTop)\n        else ls.remove(path)\n        next()\n    },\n    metaInfo() {\n        return {\n            title: '这个是带vuex的模块 - ' + this.topics.page\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/vuex/pages/view.vue",
    "content": "<template>\n    <views :data=\"item.data\" />\n</template>\n<script>\nimport { mapGetters } from 'vuex'\nimport views from '../components/view.vue'\n\nexport default {\n    name: 'vuex-view',\n    components: {\n        views\n    },\n    data() {\n        return {}\n    },\n    computed: {\n        ...mapGetters({\n            item: 'topic/getTopic'\n        })\n    },\n    async mounted() {\n        const id = this.$route.params.id\n        this.$store.dispatch('topic/getTopic', { id })\n    },\n    metaInfo() {\n        return {\n            title: this.item.data.title\n        }\n    }\n}\n</script>\n"
  },
  {
    "path": "src/modules/vuex/router/index.js",
    "content": "/* eslint-disable no-inline-comments */\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\n// 正常打包\n// import index from '../pages/index.vue'\n// import view from '../pages/view.vue'\n// 懒加载\n// const index = resolve => require(['../pages/index.vue'], resolve)\n// const view = resolve => require(['../pages/view.vue'], resolve)\n// 懒加载 - 按组\n// const index = r => require.ensure([], () => r(require('../pages/index.vue')), 'group-index')\n// const view = r => require.ensure([], () => r(require('../pages/view.vue')), 'group-view')\n// 懒加载 - 按组 import\nconst index = () => import(/* webpackChunkName: \"vuex-index\" */ '../pages/index.vue')\nconst view = () => import(/* webpackChunkName: \"vuex-view\" */ '../pages/view.vue')\n\nVue.use(VueRouter)\n\nconst router = new VueRouter({\n    mode: 'hash',\n    //base: __dirname,\n    routes: [\n        { name: 'index', path: '/', component: index },\n        { name: 'view', path: '/view/:id', component: view }\n    ]\n})\n\nexport default router\n"
  },
  {
    "path": "src/modules/vuex/store/index.js",
    "content": "import Vue from 'vue'\nimport Vuex from 'vuex'\nimport topics from './modules/topics'\nimport topic from './modules/topic'\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n    modules: {\n        topics,\n        topic\n    }\n})\n"
  },
  {
    "path": "src/modules/vuex/store/modules/topic.js",
    "content": "import api from '@/api'\n\nconst state = {\n    item: {\n        data: {},\n        path: ''\n    }\n}\n\nconst actions = {\n    async ['getTopic'](\n        {\n            commit,\n            state,\n            rootState: {\n                route: { fullPath }\n            }\n        },\n        config\n    ) {\n        const path = fullPath\n        if (state.item.data.id && path === state.item.path) {\n            return\n        }\n        const { data, success } = await api.get(`topic/${config.id}`)\n        if (data && success) {\n            commit('receiveTopic', {\n                data,\n                path\n            })\n        }\n    }\n}\n\nconst mutations = {\n    ['receiveTopic'](state, { data, path }) {\n        state.item = {\n            data,\n            path\n        }\n    }\n}\n\nconst getters = {\n    ['getTopic'](state) {\n        return state.item\n    }\n}\n\nexport default {\n    namespaced: true,\n    state,\n    actions,\n    mutations,\n    getters\n}\n"
  },
  {
    "path": "src/modules/vuex/store/modules/topics.js",
    "content": "import api from '@/api'\n\nconst state = {\n    lists: {\n        data: [],\n        page: 1,\n        path: ''\n    }\n}\n\nconst actions = {\n    async ['getTopics'](\n        {\n            commit,\n            state,\n            rootState: {\n                route: { fullPath }\n            }\n        },\n        config\n    ) {\n        const path = fullPath\n        if (state.lists.data.length > 0 && path === state.lists.path && config.page === 1) {\n            return\n        }\n        const { data, success } = await api.get('topics', config)\n        if (data && success) {\n            commit('receiveTopics', {\n                ...config,\n                data,\n                path\n            })\n        }\n    }\n}\n\nconst mutations = {\n    ['receiveTopics'](state, { data, page, path }) {\n        let list\n        if (page === 1) {\n            list = [].concat(data)\n        } else {\n            list = state.lists.data.concat(data)\n        }\n        state.lists = {\n            data: list,\n            page,\n            path\n        }\n    }\n}\n\nconst getters = {\n    ['getTopics'](state) {\n        return state.lists\n    }\n}\n\nexport default {\n    namespaced: true,\n    state,\n    actions,\n    mutations,\n    getters\n}\n"
  },
  {
    "path": "src/polyfill/index.js",
    "content": "import 'core-js/features/promise'\nimport 'core-js/features/array/find'\nimport 'core-js/features/array/find-index'\nimport 'core-js/features/array/includes'\n"
  },
  {
    "path": "src/utils/index.js",
    "content": "import toastr from 'toastr'\ntoastr.options.positionClass = 'toast-top-center'\n\nfunction pluralize(time, label) {\n    return time + label\n}\n\nexport const setMessage = config => {\n    let content, type\n    if (typeof config === 'string') {\n        content = config\n        type = 'error'\n    } else {\n        content = config.content\n        type = config.type\n    }\n    toastr[type](content)\n}\n\nexport const strlen = str => {\n    let charCode = -1\n    const len = str.length\n    let realLength = 0\n    for (let i = 0; i < len; i++) {\n        charCode = str.charCodeAt(i)\n        if (charCode >= 0 && charCode <= 128) realLength += 1\n        else realLength += 2\n    }\n    return realLength\n}\n\nexport function timeAgo(time) {\n    const preg = /^[\\d]+$/\n    const timestamp = preg.test(time)\n    if (!timestamp) {\n        const tmp = Date.parse(time)\n        time = tmp / 1000\n    }\n    const between = Date.now() / 1000 - Number(time)\n    if (between < 60) {\n        return '刚刚'\n    } else if (between < 3600) {\n        return pluralize(parseInt(between / 60, 10), ' 分钟前')\n    } else if (between < 86400) {\n        return pluralize(parseInt(between / 3600, 10), ' 小时前')\n    }\n    return pluralize(parseInt(between / 86400, 10), ' 天前')\n}\n\nexport const timeYmd = timestamp => {\n    var time = new Date(timestamp * 1000)\n    var year = time.getFullYear()\n    var month = time.getMonth() + 1\n    var date = time.getDate()\n    return year + '-' + (month < 10 ? '0' + month : month) + '-' + (date < 10 ? '0' + date : date)\n}\n"
  },
  {
    "path": "vue.config.js",
    "content": "/* eslint-disable no-inline-comments */\nconst entris = require('./entris')\nconst pages = {}\nObject.keys(entris).forEach(item => {\n    pages[item] = {\n        // page 的入口\n        entry: 'src/modules/' + item + '/index.js',\n        // 模板来源\n        template: 'public/index.html',\n        // 在 dist/index.html 的输出\n        filename: item + '.html'\n    }\n})\n\nmodule.exports = {\n    publicPath: '/',\n    // publicPath: '/vue2-multiple-entry/',\n    pages,\n    configureWebpack: {\n        devtool: 'source-map',\n        performance: {\n            hints: 'warning',\n            maxAssetSize: 30000000, // 单位为字节\n            maxEntrypointSize: 50000000, // 单位为字节\n            assetFilter(assetFilename) {\n                // 提供资源文件名的断言函数\n                return assetFilename.endsWith('.css') || assetFilename.endsWith('.js')\n            }\n        }\n    },\n    chainWebpack: config => {\n        config.module\n            .rule('vue')\n            .use('vue-loader')\n            .tap(options => {\n                options.compilerOptions.preserveWhitespace = true\n                return options\n            })\n        config.module.rule('eslint').uses.clear()\n        config.module.rule('eslint').clear()\n    },\n    css: {\n        loaderOptions: {}\n    },\n    pluginOptions: {},\n    devServer: {\n        port: 8086,\n        host: '0.0.0.0',\n        hot: true,\n        disableHostCheck: true,\n        proxy: {\n            '/api': {\n                target: 'http://localhost:4000',\n                changeOrigin: true,\n                pathRewrite: {\n                    '^/api': '/api'\n                }\n            }\n        },\n        historyApiFallback: {\n            rewrites: [\n                // shows views/landing.html as the landing page\n                { from: /^\\/$/, to: '/index.html' },\n                // shows views/subpage.html for all routes starting with /subpage\n                { from: /^\\/module2/, to: '/module2.html' },\n                { from: /^\\/module3/, to: '/module3.html' },\n                { from: /^\\/router/, to: '/router.html' },\n                { from: /^\\/vuex/, to: '/vuex.html' },\n                { from: /^\\/view/, to: '/view.html' }\n            ]\n        }\n    }\n}\n"
  }
]