vue单页到多页的配置

前言

vue如果改成多页,可以减少每次渲染的包大小,每个页面也可以成为一个新的单页,可以更合理划分业务内容。分别写了html及pug两个模板引擎的多页模板,仓库地址如下:

vue单页改成多页步骤

  • 此步骤是基于上一篇vue单页项目模板搭建的,并且使用的是html模板,有不清楚的webpack配置可以去该仓库查询
  • 修改目录结构:将app目录下的pages下的页面结构修改成如下,文件夹名-js文件名-html文件名需要一致,且定义的页面路由开头也需要与文件名一致,页面内容不详讲。
    .
    ├── README.md
    ├── app // 前端目录
    │   ├── assets
    │   │   ├── images
    │   │   ├── js
    │   │   └── less
    │   ├── components
    │   └── pages
    │       ├── home
    │       │   ├── detail.vue
    │       │   ├── home.html
    │       │   ├── home.js
    │       │   └── main.vue
    │       └── user
    │           ├── main.vue
    │           ├── user.html
    │           └── user.js
    ├── back-end  // 后端服务
    ├── build  // webpack配置
    │   ├── build.js
    │   ├── utils.js
    │   ├── webpack.common.conf.js
    │   ├── webpack.dev.conf.js
    │   └── webpack.prod.conf.js
    ├── dist // 打包文件
    ├── package.json
    ├── test
    ├── webpack.config.js
    
  • 修改webpack配置
    • 修改入口配置

      // 新建文件 utils.js
      const path = require('path')
      // `glob`: 匹配文件, 该模块允许你使用 * 等符号, 例如lib/*.js就是获取lib文件夹下的所有js后缀名的文件
      const glob = require('glob')
      const PAGE_PATH = path.resolve(__dirname, '../app/pages')
      
      //多入口配置:通过js文件名
      exports.entries = function () {
        // 通过glob模块读取pages文件夹下的所有对应文件夹下的js后缀文件
        var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
        var map = {}
        entryFiles.forEach((filePath) => {
          // 获取文件名
          var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
          map[filename] = filePath
        })
        return map
      }
      

      修改入口:

        entry: utils.entries(),
      
    • 修改html生成配置

      • webpack.dev.conf.js:注释掉原来定义的HtmlWebpackPlugin,并改成下面的
        plugins: [
          // new HtmlWebpackPlugin({
          //   filename: 'index.html',
          //   title: '',
          //   template: path.join(appDir, 'index.html'),
          //   inject: true,
          //   chunks: ['app']
          // })
        ],
        
        const glob = require('glob')
        const PAGE_PATH = path.resolve(__dirname, '../app/pages')
        
        let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
        entryHtml.forEach((filePath) => {
          let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
          let conf = {
            filename: filename + '.html',
            template: filePath,
            inject: true,
            chunks: [filename], // 页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
          }
          config.plugins.push(new HtmlWebpackPlugin(conf))
        })
        
      • webpack.prod.conf.js:注释掉原来定义的HtmlWebpackPlugin,并改成下面的
       plugins: [
         // new HtmlWebpackPlugin({
         //   filename: 'index.html', 
         //   template: path.join(appDir, 'index.html'),
         //   title: '',
         //   inject: true,
         //   minify: {
         //     removeComments: true,
         //     collapseWhitespace: true,
         //     removeAttributeQuotes: true,
         //     conservativeCollapse: true
         //   },
         //   chunks: ['manifest', 'vendors', 'app']
         // }),
         new webpack.HashedModuleIdsPlugin(),
         // new InlineManifestWebpackPlugin('manifest') 
       ],
      
      const glob = require('glob')
      const PAGE_PATH = path.resolve(__dirname, '../app/pages')
      
      let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
      entryHtml.forEach((filePath) => {
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        let conf = {
          filename: filename + '.html', 
          template: filePath,
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true,
            conservativeCollapse: true
          },
          inject: true,
          chunksSortMode: 'dependency',
          chunks: ['manifest', 'vendors', filename],
        }
        config.plugins.push(new HtmlWebpackPlugin(conf))
      })
      // 需放在HtmlWebpackPlugin下面
      config.plugins.push(new InlineManifestWebpackPlugin('manifest'))
      
    • 到这步,已经可以正常执行打包npm run build,但是开发调试的时候npm run dev,发现页面输入的页面路由http://xxxx:9001/home直接404了,解决办法是,需要在devServer中配置重写操作指定页面,不然都是直接默认查找index.html页面的。

        // utils.js
        exports.rewrites = function () {
          const entries = exports.entries();
          const rewrites = [];
          Object.keys(entries).forEach((name) => {
            const reg = new RegExp(`^\/${name}`);
            rewrites.push({ from: reg, to: `\/${name}.html` });
          });
          console.log(rewrites);
          return rewrites;
        };
      
      // webpack.dev.conf.js
      devServer: {
       ...
        historyApiFallback: {
          rewrites: utils.rewrites() // 重要!路由匹配html页面,不配置则通过路由找不到页面
        }, 
        ...
      },
      
      

      配置完后就可以正常按照路由打开页面了。

    • 由于vue-router我使用了history模式的路由,打包后的页面需要在服务器端配置路由,通过后端render才可打开页面(或者你可以采用hash模式的路由,就可以直接打开html页面),我写了一个back-end的简单服务器端,到目录下执行npm run dev,,打开http://localhost:3000/home即可看到对应打包页面内容。因为,上线前,需要后端配置前端的页面路由指定的html页面。

使用pug模板引擎

  • 安装依赖
    npm install -save-dev pug pug-loader
    
  • 修改webpack配置
    • webpack.common.conf.js,增加pug-loader
      module: {
        rules: [
          ...
          {
            test: /\.pug$/,
            loader: 'pug-loader'
          },
        ]
      },
      
    • webpack.dev.conf.js & webpack.prod.conf.js,修改入口文件后缀
      - let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
      + let entryHtml = glob.sync(PAGE_PATH + '/*/*.pug')
      
  • 修改页面模板
    .
    ├── README.md
    ├── app // 前端目录
         ├── assets
         │   ├── images
         │   ├── js
         │   ├── layout
         │   │     └── base.pug // 新增公共pug
         │   └── less
         ├── components
         └── pages
             ├── home
             │   ├── detail.vue
             │   ├── home.pug  // 修改文件后缀及内容
             │   ├── home.js
             │   └── main.vue
             └── user
                 ├── main.vue
                 ├── user.pug  // 修改文件后缀及内容
                 └── user.js
    
    

参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345