vue-cli+webpack搭建一個多頁面應用

2021-04-18 07:00:08

什麼是單頁面應用和多頁面應用?

SPA單頁面應用:指的是隻有一個主頁面的應用(只有一個html頁面),專案啟動時載入主頁面時會一次性載入所有的js、css等相關資源(需要進行首屏優化)。所有內容都包含在主頁面中,對每一個功能模組元件化。單頁面的跳轉實質上就是切換相關元件,僅僅重新整理區域性資源。
MPA多頁面應用:指的是有多個獨立的頁面(多個HTML頁面),開啟不同的頁面時會載入相關的js以及css資源,公共資源會重複載入。多頁面應用跳轉,需要整個頁面進行重新整理。

單頁面和多頁面的區別

1、重新整理方式

  • SPA:相關元件的切換,頁面區域性重新整理;
  • MPA:整個頁面進行重新整理。

2、路由模式

  • SPA:可以使用hash,也可以使用history;
  • MPA:普通連結跳轉。

3、使用者體驗

  • SPA:頁面片段間切換快,使用者體驗效果好,但初次載入檔案過多,需要做相關優化;
  • MPA:頁面切換緩慢,流暢度不夠,使用者體驗效果較差;

4、資料傳遞

  • SPA:容易實現資料傳遞(路由帶引數傳值、Vuex傳值等);
  • MPA:依賴url傳值、cookie、本地session。

5、使用範圍

  • SPA:高要求的體驗度,追求介面流暢的應用;
  • MPA:適用於追求高度支援搜尋引擎的應用。

如何使用vue-cli+webpack初始化一個專案?

1、使用vue init webpack "專案名"
在這裡插入圖片描述
2、完成後,使用cd "專案檔名"npm isntall 安裝依賴,最後使用npm run dev啟動專案。

vue-cli+webpack搭建多頁面應用

有了上面的概念以及專案基礎搭建,我們可以在vue-cli腳手架搭建的SPA專案上做一些修改,使其變成MPA應用。

專案結構調整

在這裡插入圖片描述
首先,可以建立一下下面紅色方框的目錄結構,需要注意的是我們需要把mian.js檔案改名為index.js,保證頁面入口js檔案和模板檔名保持一致,上面紅色方框的檔案是webpack初始化的檔案。

webpack設定更改

1、在build/utils.js中我們新增兩個方法,分別為多入口檔案和多頁面輸出。

const path = require('path')
const glob = require('glob')
const PAGE_PATH = path.resolve(__dirname, '../src/pages');
const HtmlWebpackPlugin = require('html-webpack-plugin');   //對每個頁面單獨打包生成一個新頁面的外掛
const merge = require('webpack-merge')
// 多入口設定
exports.entries = function() {
  var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
  var map = {}
  entryFiles.forEach((filePath) => {
    // /index.js
    var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))     // index
    map[filename] = filePath;           // map[index] = PAGE_PATH + /index/index.js
  })
  return map;
}

// 多頁面輸出設定
exports.htmlPlugin  = function() {
  let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
  let arr = []
  entryHtml.forEach((filePath) => {
    let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
    let conf = {
      template: filePath,
      filename: filename + '.html',
      chunks: [filename],
      inject: true
    }
    if(process.env.NODE_ENV === 'production') {
      conf = merge(conf, {
        chunks: ['manifest', 'vendor', filename],
        minify: {
          removeComments: true,
          collapseWhitespace: true,
          removeAttributeQuotes: true
        },
        chunksSortMode: 'dependency'
      })
    }
    arr.push(new HtmlWebpackPlugin(conf))
  })
  return arr
}

2、修改build/webpack.base.conf.js的入口設定。

 entry: {
    app: './src/main.js',
    }
   更換為   
 entry: utils.entries(),

3、修改build/webpack.dev.conf.js和build/webpack.prod.conf.js的多頁面設定:把原有的頁面模板設定註釋或刪除,並把多頁面設定新增到plugins。

  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          warnings: false
        }
      },
      sourceMap: config.build.productionSourceMap,
      parallel: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      // Setting the following option to `false` will not extract CSS from codesplit chunks.
      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
      allChunks: true,
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin({
      cssProcessorOptions: config.build.productionSourceMap
        ? { safe: true, map: { inline: false } }
        : { safe: true }
    }),
    // generate dist index.html with correct asset hash for caching.
    // you can customize output by editing /index.html
    // see https://github.com/ampedandwired/html-webpack-plugin
  //   new HtmlWebpackPlugin({
  //     filename: config.build.index,
  //     template: 'index.html',
  //     inject: true,
  //     minify: {
  //       removeComments: true,
  //       collapseWhitespace: true,
  //       removeAttributeQuotes: true
  //       // more options:
  //       // https://github.com/kangax/html-minifier#options-quick-reference
  //     },
  //     // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  //     chunksSortMode: 'dependency',
  //     chunks: ['manifest', 'vendor', 'app'],
  //   }),
    // keep module.id stable when vendor modules does not change
    new webpack.HashedModuleIdsPlugin(),
    // enable scope hoisting
    new webpack.optimize.ModuleConcatenationPlugin(),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),
    // This instance extracts shared chunks from code splitted chunks and bundles them
    // in a separate chunk, similar to the vendor chunk
    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
    new webpack.optimize.CommonsChunkPlugin({
      name: 'app',
      async: 'vendor-async',
      children: true,
      minChunks: 3
    }),

    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ].concat(utils.htmlPlugin())    // 重點

文章參考資料:
Vue單頁面與多頁面的區別
碼雲地址