多页面项目实现

274 阅读1分钟

一. 目标

  • /src/view内,一个文件夹输出一个页面
  • 自动配置vue.config.js内的pages字段
  • 不使用vue的router

二. 实现

1.vue-cli3基本配置

  • 文件结构如下 去掉了src文件夹下的主入口文件,views文件夹下的文件夹内,一个文件夹生成一个页面

image.png

  • vue.config.js配置 主要是vue.config.js下的pages字段, 指定多页面的入口,模板,输出文件等等, 配置路径
const path = require('path');

console.log('当前环境变量NODE_ENV:', process.env.NODE_ENV);

module.exports = {
    // 配置多页应用
    pages: {
        index: {
            // page 的入口
            entry: 'src/main.js',
            // 模板来源
            template: 'public/index.html',
            // 在 dist/index.html 的输出
            filename: 'index.html',
            // 当使用 title 选项时,
            // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
            title: 'Index Page',
            // 在这个页面中包含的块,默认情况下会包含
            // 提取出来的通用 chunk 和 vendor chunk。
            chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        introduce: {
            entry: 'src/introduce.js',
            template: 'public/introduce.html',
            filename: 'introduce.html'
        }
    },
    ...
}
...

2. 自动配置pages字段

common.config.js文件

const fs = require('fs');
const join = require('path').join;

const fileList = [];
const VIEW_PATH = 'src/views';
// 读取文件夹
function readDirs(path) {
    let dirList = fs.readdirSync(path);
    dirList.forEach((item, index) => {
        readFilesOfDir(path, item);
    });
}

// 读取文件
function readFilesOfDir(path, dirName) {
    const dirPath = join(path, dirName);
    const stat = fs.statSync(dirPath);
    // 读取文件夹下的所有文件, 检查是否存在和文件夹名称相同的三个文件(dirName.html, dirName.vue, dirName.js)
    if (stat.isDirectory()) {
        const files = fs.readdirSync(dirPath);
        const filesObj = array2obeject(files, dirName);
        fileList.push(filesObj);
    }
}

// 验证文件夹文件正确性
function vertify(list) {
    let flag = true;
    for (let i = 0, iLen = list.length; i < iLen; i++) {
        const item = list[i];
        const necessaryFiles = [`${item.dirName}.html`, `${item.dirName}.js`, `${item.dirName}.vue`];
        for (let j = 0, jLen = necessaryFiles.length; j < jLen; j++) {
            const subItem = necessaryFiles[j];
            if (!item.hasOwnProperty(subItem)) {
                console.error(`-------------------${item.dirName}缺少文件${subItem}, 请修改!-------------------`);
                flag = false;
                break;
            }
        }
        if (flag) {
            console.log(`${item.dirName}文件夹文件结构验证通过!`);
        }
        if (!flag) {
            break;
        }
    }
    return flag;
}

// 数组转为对象
function array2obeject(list, dirName) {
    const obj = {};
    for (const key in list) {
        obj[list[key]] = list[key];
    }
    obj.dirName = dirName;
    return obj;
}

// 生成pages
function createPageParams() {
    readDirs(VIEW_PATH);
    const flag = vertify(fileList);
    let pages = {};
    if (flag) {
        fileList.forEach(ele => {
            const dirName = ele.dirName;
            pages[dirName] = {
                // page 的入口
                entry: `${VIEW_PATH}/${dirName}/${dirName}.js`,
                // 模板来源
                template: `${VIEW_PATH}/${dirName}/${dirName}.html`,
                // 在 dist/home.html 的输出
                filename: `${dirName}.html`
            }
        });
    }
    return pages;
}

// 生成pages变量
module.exports = {
    createPageParams: createPageParams
}

vue.config.js调用示例

const path = require('path');
const common = require('./common.config');
const pages = common.createPageParams();

console.log('当前环境变量NODE_ENV:', process.env.NODE_ENV);

module.exports = {
    pages: pages,
    chainWebpack: config => {
        const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
        types.forEach(type => addStyleResource(config.module.rule('scss').oneOf(type)))
        if (process.env.NODE_ENV === 'production') {
            config.set('externals', {
                vue: 'Vue',
                'vue-router': 'VueRouter',
                'lodash': '_'
            });
        }
    },
}

function addStyleResource (rule) {
    rule.use('style-resource')
        .loader('style-resources-loader')
        .options({
            patterns: [
                path.resolve(__dirname, './src/styles/common.scss'),
            ],
        })
}