手把手教你 vue-cli 單頁到多頁應用

vue-cli 到多頁應用

前言:我有一個 cli 創建的 vue 項目,但是我想做成多頁應用,怎麼辦,廢話不多說,直接開擼~_

約定:新增代碼部分在 //add 和 //end 中間 刪除 (註釋) 代碼部分在 //del 和 //end 中間,很多東西都寫在註釋裏_

第一步:cli 一個 vue 項目

新建一個 vue 項目 官網:

 
  
  1. vue init webpack demo

cli 默認使用 webpack 的 dev-server 服務,這個服務是做不了單頁的,需要手動建一個私服叫啥你隨意 一般叫 dev.server 或者 dev.client

第二步:添加兩個方法處理出口入口文件(SPA 默認寫死的)

進入剛剛創建 vue 項目

 
  
  1. cd demo

在目錄下面找到 build/utils.js 文件,修改部分,utils.js

 
  
  1. 'use strict'

  2. const path = require('path')

  3. const config = require('../config')

  4. const ExtractTextPlugin = require('extract-text-webpack-plugin')

  5. const packageConfig = require('../package.json')

  6. //add

  7. const glob = require('glob');

  8. const HtmlWebpackPlugin = require('html-webpack-plugin');   //功能:生成html文件及js文件並把js引入html

  9. const pagePath = path.resolve(__dirname, '../src/views/');  //頁面的路徑,比如這裏我用的views,那麼後面私服加入的文件監控器就會從src下面的views下面開始監控文件

  10. //end

  11. exports.assetsPath = function (_path) {

  12.  const assetsSubDirectory = process.env.NODE_ENV === 'production'

  13.    ? config.build.assetsSubDirectory

  14.    : config.dev.assetsSubDirectory

  15.  return path.posix.join(assetsSubDirectory, _path)

  16. }

  17. exports.cssLoaders = function (options) {

  18.  options = options || {}

  19.  const cssLoader = {

  20.    loader: 'css-loader',

  21.    options: {

  22.      sourceMap: options.sourceMap

  23.    }

  24.  }

  25.  const postcssLoader = {

  26.    loader: 'postcss-loader',

  27.    options: {

  28.      sourceMap: options.sourceMap

  29.    }

  30.  }

  31.  // generate loader string to be used with extract text plugin

  32.  function generateLoaders (loader, loaderOptions) {

  33.    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

  34.    if (loader) {

  35.      loaders.push({

  36.        loader: loader + '-loader',

  37.        options: Object.assign({}, loaderOptions, {

  38.          sourceMap: options.sourceMap

  39.        })

  40.      })

  41.    }

  42.    // Extract CSS when that option is specified

  43.    // (which is the case during production build)

  44.    if (options.extract) {

  45.      return ExtractTextPlugin.extract({

  46.        use: loaders,

  47.        fallback: 'vue-style-loader'

  48.      })

  49.    } else {

  50.      return ['vue-style-loader'].concat(loaders)

  51.    }

  52.  }

  53.  // https://vue-loader.vuejs.org/en/configurations/extract-css.html

  54.  return {

  55.    css: generateLoaders(),

  56.    postcss: generateLoaders(),

  57.    less: generateLoaders('less'),

  58.    sass: generateLoaders('sass', { indentedSyntax: true }),

  59.    scss: generateLoaders('sass'),

  60.    stylus: generateLoaders('stylus'),

  61.    styl: generateLoaders('stylus')

  62.  }

  63. }

  64. // Generate loaders for standalone style files (outside of .vue)

  65. exports.styleLoaders = function (options) {

  66.  const output = []

  67.  const loaders = exports.cssLoaders(options)

  68.  for (const extension in loaders) {

  69.    const loader = loaders[extension]

  70.    output.push({

  71.      test: new RegExp('\\.' + extension + '$'),

  72.      use: loader

  73.    })

  74.  }

  75.  return output

  76. }

  77. exports.createNotifierCallback = () => {

  78.  const notifier = require('node-notifier')

  79.  return (severity, errors) => {

  80.    if (severity !== 'error') return

  81.    const error = errors[0]

  82.    const filename = error.file && error.file.split('!').pop()

  83.    notifier.notify({

  84.      title: packageConfig.name,

  85.      message: severity + ': ' + error.name,

  86.      subtitle: filename || '',

  87.      icon: path.join(__dirname, 'logo.png')

  88.    })

  89.  }

  90. }

  91. //add  新增一個方法處理入口文件(單頁應用的入口都是寫死,到時候替換成這個方法)

  92. exports.createEntry = () => {

  93.  let files = glob.sync(pagePath + '/**/*.js');

  94.  let entries = {};

  95.  let basename;

  96.  let foldername;

  97.  files.forEach(entry => {

  98.    // Filter the router.js

  99.    basename = path.basename(entry, path.extname(entry), 'router.js');

  100.    foldername = path.dirname(entry).split('/').splice(-1)[0];

  101.    // If foldername not equal basename, doing nothing

  102.    // The folder maybe contain more js files, but only the same name is main

  103.    if (basename === foldername) {

  104.      entries[basename] = process.env.NODE_ENV === 'development' ?

  105.        [

  106.          'webpack-hot-middleware/client?noInfo=true&reload=true&path=/__webpack_hmr&timeout=20000',

  107.          entry

  108.        ]: [entry];

  109.    }

  110.  });

  111.  return entries;

  112. };

  113. //end

  114. //add 新增出口文件

  115. exports.createHtmlWebpackPlugin = (publicModule) => {

  116.  let files = glob.sync(pagePath + '/**/*.html', {matchBase: true});

  117.  let entries = exports.createEntry();

  118.  let plugins = [];

  119.  let conf;

  120.  let basename;

  121.  let foldername;

  122.  publicModule = publicModule || [];

  123.  files.forEach(file => {

  124.    basename = path.basename(file, path.extname(file));

  125.    foldername = path.dirname(file).split('/').splice(-1).join('');

  126.    if (basename === foldername) {

  127.      conf = {

  128.        template: file,

  129.        filename: basename + '.html',

  130.        inject: true,

  131.        chunks: entries[basename] ? [basename] : []

  132.      };

  133.      if (process.env.NODE_ENV !== 'development') {

  134.        conf.chunksSortMode = 'dependency';

  135.        conf.minify = {

  136.          removeComments: true,

  137.          collapseWhitespace: true,

  138.          removeAttributeQuotes: true

  139.        };

  140.        // 在構建生產環境時,需要指定共用模塊

  141.        conf.chunks = [...publicModule, ...conf.chunks];

  142.      }

  143.      plugins.push(new HtmlWebpackPlugin(conf));

  144.    }

  145.  });

  146.  return plugins;

  147. };

  148. //end

第三步:創建私服(不使用 dev-server 服務,自己建一個)

從 express 新建私服並配置 (build 文件夾下新建 我這裏叫 webpack.dev.client.js)

 
  
  1. /**

  2. * created by qbyu2 on 2018-05-30

  3. * express 私服

  4. * */

  5. 'use strict';

  6. const fs = require('fs');

  7. const path = require('path');

  8. const express = require('express');

  9. const webpack = require('webpack');

  10. const webpackDevMiddleware = require('webpack-dev-middleware');   //文件監控(前面配置了從views下面監控)

  11. const webpackHotMiddleware = require('webpack-hot-middleware');   //熱加載

  12. const config = require('../config');

  13. const devWebpackConfig = require('./webpack.dev.conf');

  14. const proxyMiddleware = require('http-proxy-middleware');   //跨域

  15. const proxyTable = config.dev.proxyTable;

  16. const PORT = config.dev.port;

  17. const HOST = config.dev.host;

  18. const assetsRoot = config.dev.assetsRoot;

  19. const app = express();

  20. const router = express.Router();

  21. const compiler = webpack(devWebpackConfig);

  22. let devMiddleware  = webpackDevMiddleware(compiler, {

  23.  publicPath: devWebpackConfig.output.publicPath,

  24.  quiet: true,

  25.  stats: {

  26.    colors: true,

  27.    chunks: false

  28.  }

  29. });

  30. let hotMiddleware = webpackHotMiddleware(compiler, {

  31.  path: '/__webpack_hmr',

  32.  heartbeat: 2000

  33. });

  34. app.use(hotMiddleware);

  35. app.use(devMiddleware);

  36. Object.keys(proxyTable).forEach(false

  37.  }

  38. });

  39. let hotMiddleware = webpackHotMiddleware(compiler, {

  40.  path: '/__webpack_hmr',

  41.  heartbeat: 2000

  42. });

  43. app.use(hotMiddleware);

  44. app.use(devMiddleware);

  45. Object.keys(proxyTable).forEach(function (context) {

  46.  let options = proxyTable[context];

  47.  if (typeof options === 'string') {

  48.    options = {

  49.      target: options

  50.    };

  51.  }

  52.  app.use(proxyMiddleware(context, options));

  53. });

  54. //雙路由   私服一層控制私服路由    vue的路由控制該頁面下的路由

  55. app.use(router)

  56. app.use('/static', express.static(path.join(<

相關文章
相關標籤/搜索