vue創(chuàng)建多項目工程

我司的一個系統(tǒng)要重構(gòu),新系統(tǒng)計劃用vue開發(fā)扬卷,但是由于舊系統(tǒng)過于龐大颤介,在開發(fā)時使用分包開發(fā)(多系統(tǒng)),所以老大要求在開發(fā)新系統(tǒng)時也要分成多個系統(tǒng)跟匆。但是本人又不想在多個系統(tǒng)中維護一堆同樣的代碼(為保持風格一致异袄,需要使用公共的樣式、組件等)玛臂,遂研究如何在一個vue項目中創(chuàng)建多個系統(tǒng)烤蜕。

先根據(jù)這篇文章搭建一個可以本地訪問的多系統(tǒng)前端項目

創(chuàng)建新項目

vue create multi-project

創(chuàng)建時的選項可以自己選擇,為簡潔計迹冤,我只在基本的選擇上添加了routerstore
創(chuàng)建完成的項目結(jié)構(gòu)如下:

初始目錄結(jié)構(gòu)

使用腳手架創(chuàng)建的vue項目均為單頁應用讽营,但在此處我們需要把它修改為多頁應用。
將目錄結(jié)構(gòu)調(diào)整如下:

多系統(tǒng)工程目錄結(jié)構(gòu)

官方文檔中給出的解決方法是在vue.config.js配置項pages
官方文檔

vue.config.js配置參考文檔
修改vue.config.js文件為:

module.exports = {
  pages: {
    projectA: {
      // page 的入口
      entry: 'src/modules/projectA/main.js',
      // 模板來源
      template: 'public/index.html',
      // 在 dist/index.html 的輸出
      filename: 'projectA.html',
      // 當使用 title 選項時泡徙,
      // template 中的 title 標簽需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title: 'project A Page',
      // 在這個頁面中包含的塊橱鹏,默認情況下會包含
      // 提取出來的通用 chunk 和 vendor chunk。
      chunks: ['chunk-vendors', 'chunk-common', 'projectA']
    },
    // 當使用只有入口的字符串格式時堪藐,
    // 模板會被推導為 `public/subpage.html`
    // 并且如果找不到的話莉兰,就回退到 `public/index.html`。
    // 輸出文件名會被推導為 `subpage.html`礁竞。
    projectB: {
      // page 的入口
      entry: 'src/modules/projectB/main.js',
      // 模板來源
      template: 'public/index.html',
      // 在 dist/index.html 的輸出
      filename: 'projectB.html',
      // 當使用 title 選項時糖荒,
      // template 中的 title 標簽需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title: 'project B Page',
      // 在這個頁面中包含的塊,默認情況下會包含
      // 提取出來的通用 chunk 和 vendor chunk模捂。
      chunks: ['chunk-vendors', 'chunk-common', 'projectB']
    }
  }
}

重新啟動項目捶朵,訪問下面兩個地址即可看到多頁面的效果。
http://localhost:8080/projectA/
http://localhost:8080/projectB/
此時可以正確看到兩個項目的App頁面狂男,但在App通過router-vue暴露出去的頁面卻看不到综看,查看network報錯為We're sorry but multi-project3 doesn't work properly without JavaScript enabled. Please enable it to continue.
查資料后,把router的history修改為hash模式即可

打包部署到服務器

此時執(zhí)行npm run build打包岖食,打包結(jié)果如下(自己當時沒有截圖,借用別人的圖):

打包結(jié)構(gòu)混亂

兩個不同的項目的文件各自編譯打包红碑,但并沒有按項目分成不同的文件夾,我們進一步修改配置县耽,將其改為按項目打包句喷。
修改vue.config.js代碼如下:

var projectname = process.argv[3]
var glob = require('glob')

function getEntry() {
  var entries = {}
  if (process.env.NODE_ENV == 'production') {
    entries = {
      index: {
        // page的入口
        entry: 'src/modules/' + projectname + '/main.js',
        // 模板來源
        template: 'public/index.html',
        // 在 dist/index.html 的輸出
        filename: 'index.html',
        title: projectname,
        chunks: ['chunk-vendors', 'chunk-common', 'index']
      }
    }
  } else {
    var items = glob.sync( './src/modules/*/*.js')
    for (var i in items) {
      var filepath = items[i]
      var fileList = filepath.split('/');
      var fileName = fileList[fileList.length-2];
      entries[fileName] = {
        entry: `src/modules/${fileName}/main.js`,
        // 模板來源
        template: `public/index.html`,
        // 在 dist/index.html 的輸出
        filename: `${fileName}.html`,
        // 提取出來的通用 chunk 和 vendor chunk镣典。
        chunks: ['chunk-vendors', 'chunk-common', fileName]
      }
    }
  }
  return entries
}

var pages = getEntry()
module.exports = {
  productionSourceMap: false, // 生產(chǎn)禁止顯示源代碼
  outputDir: 'dist/' + projectname,
  pages: pages
}

現(xiàn)在執(zhí)行以下命令進行打包:

#  npm run build [projectFileName]
npm run build projectA
npm run build projectB

打包結(jié)果如下:


分項目打包

把打包好的文件放到nginx上,訪問結(jié)果如下:

image.png

跟上面是同樣的問題唾琼,請求的js404
看了下打包后的文件兄春,是打包后的文件中jscss等文件引用路徑錯誤,手動修改后可以正常訪問锡溯,所以只要修改打包配置赶舆,使文件引用路徑符合要求就可以了

此時需要參考官網(wǎng)修改vue.config.js文件

publicPath: '/',  // 原配置
publicPath: '/' + projectname + '/',  // 修改后

之后再打包的文件引用路徑就沒有問題了

把之前的單項目修改為多項目

由于我們之前已經(jīng)有一個小項目(vue單項目-修改自開源項目vue-admin-template),考慮到修改為多項目的代碼修改量不是很大祭饭,所以繼續(xù)在之前的項目中進行修改芜茵。
首先根據(jù)上面的步驟修改目錄結(jié)構(gòu)和vue.config.js文件,由于現(xiàn)有的項目采用后端返回路由倡蝙,前端進行解析的方式動態(tài)加載路由九串,所以除了views外,api寺鸥、layout猪钮、routerstore目錄也都在子項目目錄中存在。其中store中的公共部分提取到父項目中胆建,子項目中需要用到的路由部分留在子項目中烤低。
目前為止,項目可以正常訪問笆载,只是公共組件SvgIcon無法使用扑馁,原因是把之前項目的vue.config.js文件中的內(nèi)容給修改了,再加回去就好了凉驻。
直接把加載svg的配置加進去會報錯Error: Cannot call .tap() on a plugin that has not yet been defined. Call plugin('preload').use(<Plugin>) first.:

image.png

參考文章修改如下:
修改前:

config.plugin('preload').tap(() => [
      {
        rel: 'preload',
        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
        include: 'initial'
      }
    ])

修改后:

const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");

config.plugin('preload').use(PreloadWebpackPlugin).tap(() => [
      {
        rel: 'preload',
        // to ignore runtime.js
        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
        include: 'initial'
      }
    ])

此時便可以正常使用SvgIcon組件了
此時vue.config.js文件如下:

'use strict'

const projectname = process.argv[3]
const glob = require('glob')

const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");

function getEntry() {
  let entries = {}
  if (process.env.NODE_ENV == 'production') {
    entries = {
      index: {
        // page的入口
        entry: 'src/modules/' + projectname + '/main.js',
        // 模板來源
        template: 'public/index.html',
        // 在 dist/index.html 的輸出
        filename: 'index.html',
        title: projectname,
        chunks: ['chunk-vendors', 'chunk-common', 'index']
      }
    }
  } else {
    let items = glob.sync( './src/modules/*/*.js')
    for (let i in items) {
      let filepath = items[i]
      let fileList = filepath.split('/');
      let fileName = fileList[fileList.length-2];
      entries[fileName] = {
        entry: `src/modules/${fileName}/main.js`,
        // 模板來源
        template: `public/index.html`,
        // 在 dist/index.html 的輸出
        filename: `${fileName}.html`,
        // 提取出來的通用 chunk 和 vendor chunk腻要。
        chunks: ['chunk-vendors', 'chunk-common', fileName]
      }
    }
  }
  return entries
}

let pages = getEntry()

const path = require('path')
const defaultSettings = require('./src/settings.js')

function resolve(dir) {
  return path.join(__dirname, dir)
}

const name = defaultSettings.title || 'vue Admin Template' // page title

// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following methods:
// port = 9528 npm run dev OR npm run dev --port = 9528
const port = process.env.port || process.env.npm_config_port || 9528 // dev port

// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
  /**
   * You will need to set publicPath if you plan to deploy your site under a sub path,
   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
   * then publicPath should be set to "/bar/".
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   */
  outputDir: 'dist/' + projectname,
  publicPath: '/' + projectname + '/',
  pages: pages,
  assetsDir: 'static',
  lintOnSave: process.env.NODE_ENV === 'development',
  productionSourceMap: false,
  devServer: {
    host: '0.0.0.0',
    port: port,
    open: true,
    https: true,
    overlay: {
      warnings: false,
      errors: true
    },
    before: require('./mock/mock-server.js'),
    proxy: {
      '/downloadFile': {
        // target: 'http://10.141.128.102:8401',
        // target: 'http://dhr-basic-service.apps.uat.taikangcloud.com/', //test
        target: 'http://127.0.0.1:88', //dev
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          '^/downloadFile': '/'
        }
      },
    },
  },
  configureWebpack: {
    // provide the app's title in webpack's name field, so that
    // it can be accessed in index.html to inject the correct title.
    name: name,
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
  },
  chainWebpack(config) {
    // it can improve the speed of the first screen, it is recommended to turn on preload
    config.plugin('preload').use(PreloadWebpackPlugin).tap(() => [
      {
        rel: 'preload',
        // to ignore runtime.js
        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
        // fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/], // 文件黑名單
        fileBlacklist: [/\.map$/, /hot-update\.js$/],
        include: 'initial'
      }
    ])

    // when there are many pages, it will cause too many meaningless requests
    config.plugins.delete('prefetch')

    // set svg-sprite-loader
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end()
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()

    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
          config
            .plugin('ScriptExtHtmlWebpackPlugin')
            .after('html')
            .use('script-ext-html-webpack-plugin', [{
            // `runtime` must same as runtimeChunk name. default is `runtime`
              inline: /runtime\..*\.js$/
            }])
            .end()
          config
            .optimization.splitChunks({
              chunks: 'all',
              cacheGroups: {
                libs: {
                  name: 'chunk-libs',
                  test: /[\\/]node_modules[\\/]/,
                  priority: 10,
                  chunks: 'initial' // only package third parties that are initially dependent
                },
                elementUI: {
                  name: 'chunk-elementUI', // split elementUI into a single package
                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
                },
                commons: {
                  name: 'chunk-commons',
                  test: resolve('src/components'), // can customize your rules
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true
                }
              }
            })
          // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
          config.optimization.runtimeChunk('single')
        }
      )
  }
}

但是,我又雙叕發(fā)現(xiàn)問題啦Q爻蕖4车凇市栗!
打包部署到nginx后缀拭,有一個runtime.**.js文件找不到

找不到runtime.**.js

找了半天沒找到好方法,最后把vue.config.js文件中的最后一個config注釋掉后好了
但是這個配置這兒不太熟填帽,別人寫的配置也看不太懂蛛淋,之后可能會遇到其他問題,到時候自求多福吧
修改后的vue.config.js文件如下:

'use strict'

const projectname = process.argv[3]
const glob = require('glob')

const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");

function getEntry() {
  let entries = {}
  if (process.env.NODE_ENV == 'production') {
    entries = {
      index: {
        // page的入口
        entry: 'src/modules/' + projectname + '/main.js',
        // 模板來源
        template: 'public/index.html',
        // 在 dist/index.html 的輸出
        filename: 'index.html',
        title: projectname,
        chunks: ['chunk-vendors', 'chunk-common', 'index']
      }
    }
  } else {
    let items = glob.sync( './src/modules/*/*.js')
    for (let i in items) {
      let filepath = items[i]
      let fileList = filepath.split('/');
      let fileName = fileList[fileList.length-2];
      entries[fileName] = {
        entry: `src/modules/${fileName}/main.js`,
        // 模板來源
        template: `public/index.html`,
        // 在 dist/index.html 的輸出
        filename: `${fileName}.html`,
        // 提取出來的通用 chunk 和 vendor chunk篡腌。
        chunks: ['chunk-vendors', 'chunk-common', fileName]
      }
    }
  }
  return entries
}

let pages = getEntry()

const path = require('path')
const defaultSettings = require('./src/settings.js')

function resolve(dir) {
  return path.join(__dirname, dir)
}

const name = defaultSettings.title || 'vue Admin Template' // page title

// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following methods:
// port = 9528 npm run dev OR npm run dev --port = 9528
const port = process.env.port || process.env.npm_config_port || 9528 // dev port

// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
  /**
   * You will need to set publicPath if you plan to deploy your site under a sub path,
   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
   * then publicPath should be set to "/bar/".
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   */
  outputDir: 'dist/' + projectname,
  publicPath: '/' + projectname + '/',
  pages: pages,
  assetsDir: 'static',
  lintOnSave: process.env.NODE_ENV === 'development',
  productionSourceMap: false,
  devServer: {
    host: '0.0.0.0',
    port: port,
    open: true,
    https: true,
    overlay: {
      warnings: false,
      errors: true
    },
    before: require('./mock/mock-server.js'),
    proxy: {
      '/downloadFile': {
        // target: 'http://10.141.128.102:8401',
        // target: 'http://dhr-basic-service.apps.uat.taikangcloud.com/', //test
        target: 'http://127.0.0.1:88', //dev
        changeOrigin: true,
        ws: true,
        pathRewrite: {
          '^/downloadFile': '/'
        }
      },
    },
  },
  configureWebpack: {
    // provide the app's title in webpack's name field, so that
    // it can be accessed in index.html to inject the correct title.
    name: name,
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
  },
  chainWebpack(config) {
    // it can improve the speed of the first screen, it is recommended to turn on preload
    config.plugin('preload').use(PreloadWebpackPlugin).tap(() => [
      {
        rel: 'preload',
        // to ignore runtime.js
        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/], // 文件黑名單
        include: 'initial'
      }
    ])

    // when there are many pages, it will cause too many meaningless requests
    config.plugins.delete('prefetch')

    // set svg-sprite-loader
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end()
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()

    // config
    //   .when(process.env.NODE_ENV !== 'development',
    //     config => {
    //       config
    //         .plugin('ScriptExtHtmlWebpackPlugin')
    //         .after('html')
    //         .use('script-ext-html-webpack-plugin', [{
    //         // `runtime` must same as runtimeChunk name. default is `runtime`
    //           inline: /runtime\..*\.js$/
    //         }])
    //         .end()
    //       config
    //         .optimization.splitChunks({
    //           chunks: 'all',
    //           cacheGroups: {
    //             libs: {
    //               name: 'chunk-libs',
    //               test: /[\\/]node_modules[\\/]/,
    //               priority: 10,
    //               chunks: 'initial' // only package third parties that are initially dependent
    //             },
    //             elementUI: {
    //               name: 'chunk-elementUI', // split elementUI into a single package
    //               priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
    //               test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
    //             },
    //             commons: {
    //               name: 'chunk-commons',
    //               test: resolve('src/components'), // can customize your rules
    //               minChunks: 3, //  minimum common number
    //               priority: 5,
    //               reuseExistingChunk: true
    //             }
    //           }
    //         })
    //       // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
    //       config.optimization.runtimeChunk('single')
    //     }
    //   )
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末褐荷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嘹悼,更是在濱河造成了極大的恐慌叛甫,老刑警劉巖层宫,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異其监,居然都是意外死亡萌腿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門抖苦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來毁菱,“玉大人,你說我怎么就攤上這事锌历≈樱” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵究西,是天一觀的道長窗慎。 經(jīng)常有香客問我,道長卤材,這世上最難降的妖魔是什么捉邢? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮商膊,結(jié)果婚禮上伏伐,老公的妹妹穿的比我還像新娘。我一直安慰自己晕拆,他們只是感情好藐翎,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著实幕,像睡著了一般吝镣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昆庇,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天末贾,我揣著相機與錄音,去河邊找鬼整吆。 笑死拱撵,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的表蝙。 我是一名探鬼主播拴测,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼府蛇!你這毒婦竟也來了集索?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎务荆,沒想到半個月后妆距,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡函匕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年毅厚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浦箱。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡吸耿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酷窥,到底是詐尸還是另有隱情咽安,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布蓬推,位于F島的核電站妆棒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏沸伏。R本人自食惡果不足惜糕珊,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望毅糟。 院中可真熱鬧红选,春花似錦、人聲如沸姆另。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迹辐。三九已至蝶防,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間明吩,已是汗流浹背间学。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留印荔,地道東北人低葫。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像躏鱼,于是被迫代替她去往敵國和親氮采。 傳聞我的和親對象是個殘疾皇子殷绍,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容