阐述 Vue CLI 中的多页应用 (MPA) 配置和优化策略。

各位靓仔靓女们,晚上好!我是你们的老朋友,今天咱们聊聊 Vue CLI 多页应用(MPA)的那些事儿。

先声明,我不是什么“编程专家”,只是个在代码堆里摸爬滚打多年的老兵。咱们今天就是唠嗑,把 MPA 这玩意儿扒个底朝天,争取让大家听完能上手就干!

开场白:单页应用(SPA)虽好,但 MPA 也有春天!

现在 SPA 好像成了主流,各种框架都在推。SPA 确实爽,用户体验好,切换流畅。但是!它也有缺点,比如 SEO 不友好,首屏加载慢等等。这时候,MPA 就有了用武之地。

MPA 简单粗暴,每个页面都是独立的,SEO 友好,首屏加载也快。当然,它也有缺点,比如页面切换可能会有白屏,公共资源不好管理等等。所以,选择 SPA 还是 MPA,要根据你的项目实际情况来决定。

第一章:Vue CLI 搭建 MPA 项目:手把手教你填坑!

Vue CLI 搭建 MPA 项目,其实很简单,但是一不小心就会掉坑里。咱们一步一步来,保证大家不迷路。

  1. 安装 Vue CLI:

    如果你还没装 Vue CLI,先把它装上:

    npm install -g @vue/cli
    # OR
    yarn global add @vue/cli
  2. 创建项目:

    vue create my-mpa-project

    选择 Manually select features,然后选择 BabelRouterVuexCSS Pre-processorsLinter / Formatter 这些常用的功能(当然,你可以根据自己的需求选择)。

    然后选择 Use history mode for router?,这里我们选择 No,因为 MPA 不需要 history 模式。

    CSS 预处理器可以选一个你喜欢的,比如 Sass/SCSS (with dart-sass)

    Linter / Formatter 可以选择 ESLint + Standard config 或者 ESLint + Prettier

    最后选择 Lint on saveCommit

  3. 配置 vue.config.js

    这是 MPA 的关键!在项目的根目录下,创建一个 vue.config.js 文件,然后写入以下配置:

    module.exports = {
      pages: {
        index: {
          entry: 'src/pages/index/main.js',
          template: 'public/index.html',
          filename: 'index.html',
          title: 'Index Page',
          chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        about: {
          entry: 'src/pages/about/main.js',
          template: 'public/about.html',
          filename: 'about.html',
          title: 'About Page',
          chunks: ['chunk-vendors', 'chunk-common', 'about']
        }
      },
      // 其他配置...
    };

    这个 pages 对象就是 MPA 的核心配置。每个 key 代表一个页面,比如 indexabout。每个页面都有以下属性:

    • entry:入口文件,每个页面都有一个独立的入口文件。
    • template:HTML 模板文件,每个页面都可以有自己的模板。
    • filename:输出的文件名,比如 index.htmlabout.html
    • title:页面的标题,会设置 <title> 标签。
    • chunks:指定要包含的 chunk,比如 chunk-vendorschunk-commonindex
  4. 创建页面目录和文件:

    按照 vue.config.js 里的配置,创建对应的目录和文件:

    src/
      pages/
        index/
          main.js
          App.vue
        about/
          main.js
          App.vue
    public/
      index.html
      about.html

    main.js 负责初始化 Vue 实例,App.vue 是页面的根组件。

  5. 修改 public/index.htmlpublic/about.html

    在 HTML 文件里,修改 <title> 标签,并添加 <div id="app"></div>

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Index Page</title>
    </head>
    <body>
      <div id="app"></div>
      <!-- built files will be auto injected -->
    </body>
    </html>

    about.html 类似,只需要修改 <title> 标签即可。

  6. 启动项目:

    npm run serve
    # OR
    yarn serve

    现在,你应该能看到两个页面了:http://localhost:8080/index.htmlhttp://localhost:8080/about.html

第二章:MPA 项目优化:让你的应用飞起来!

MPA 项目搭建起来了,但是性能优化也很重要。咱们来聊聊 MPA 项目的优化策略。

  1. 公共资源提取:

    MPA 项目里,很多资源都是公共的,比如 Vue、Vue Router、Vuex、Element UI 等等。如果每个页面都引入这些资源,会造成资源浪费。所以,我们需要把这些公共资源提取出来,放到一个单独的 chunk 里。

    vue.config.js 里,配置 chainWebpack

    module.exports = {
      pages: {
        // ...
      },
      chainWebpack: config => {
        config.optimization.splitChunks({
          cacheGroups: {
            vendors: {
              name: 'chunk-vendors',
              test: /[\/]node_modules[\/]/,
              priority: -10,
              chunks: 'initial'
            },
            common: {
              name: 'chunk-common',
              minChunks: 2,
              priority: -20,
              chunks: 'initial',
              reuseExistingChunk: true
            }
          }
        });
      }
    };

    这个配置会把 node_modules 里的代码提取到 chunk-vendors.js 里,把被多个页面引用的代码提取到 chunk-common.js 里。

    然后在 pages 配置里,指定每个页面都要包含 chunk-vendorschunk-common

    module.exports = {
      pages: {
        index: {
          // ...
          chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        about: {
          // ...
          chunks: ['chunk-vendors', 'chunk-common', 'about']
        }
      },
      // ...
    };
  2. 资源预加载:

    在 MPA 项目里,页面切换的时候,浏览器会重新加载资源。如果资源比较大,会造成白屏。所以,我们需要对资源进行预加载,让浏览器提前下载资源。

    vue.config.js 里,配置 chainWebpack

    module.exports = {
      pages: {
        // ...
      },
      chainWebpack: config => {
        config.plugin('preload-index')
          .use(require('@vue/preload-webpack-plugin'), [{
            rel: 'preload',
            include: 'initial',
            fileBlacklist: [/.map$/, /chunk-vendors..*/, /chunk-common..*/]
          }]);
    
        config.plugin('preload-about')
          .use(require('@vue/preload-webpack-plugin'), [{
            rel: 'preload',
            include: 'initial',
            fileBlacklist: [/.map$/, /chunk-vendors..*/, /chunk-common..*/]
          }]);
    
        config.plugin('prefetch-index')
          .use(require('@vue/preload-webpack-plugin'), [{
            rel: 'prefetch',
            include: 'asyncChunks',
            fileBlacklist: [/.map$/]
          }]);
    
        config.plugin('prefetch-about')
          .use(require('@vue/preload-webpack-plugin'), [{
            rel: 'prefetch',
            include: 'asyncChunks',
            fileBlacklist: [/.map$/]
          }]);
      }
    };

    这个配置会使用 @vue/preload-webpack-plugin 插件,对初始加载的资源进行 preload,对异步加载的资源进行 prefetch

    • preload:告诉浏览器尽快加载资源,优先级比较高。
    • prefetch:告诉浏览器在空闲的时候加载资源,优先级比较低。
  3. 图片优化:

    图片是网页里最占体积的资源之一。所以,我们需要对图片进行优化,减小图片的大小。

    • 选择合适的图片格式: PNG 适合存储颜色较少的图片,JPEG 适合存储颜色较多的图片,WebP 适合存储各种类型的图片。
    • 压缩图片: 可以使用各种图片压缩工具,比如 TinyPNG、ImageOptim 等等。
    • 使用 CDN: 把图片放到 CDN 上,可以加快图片的加载速度。
    • 懒加载: 对于不在首屏显示的图片,可以使用懒加载,只有当图片进入可视区域的时候才加载。
  4. Gzip 压缩:

    Gzip 是一种常用的压缩算法,可以减小网页的大小,加快网页的加载速度。

    vue.config.js 里,配置 configureWebpack

    const CompressionWebpackPlugin = require('compression-webpack-plugin');
    
    module.exports = {
      pages: {
        // ...
      },
      configureWebpack: config => {
        config.plugins.push(
          new CompressionWebpackPlugin({
            filename: '[path][base].gz',
            algorithm: 'gzip',
            test: /.(js|css|html|svg)$/,
            threshold: 10240,
            minRatio: 0.8,
            deleteOriginalAssets: false
          })
        );
      }
    };

    这个配置会使用 compression-webpack-plugin 插件,对 jscsshtmlsvg 等文件进行 Gzip 压缩。

    需要注意的是,你需要配置服务器,让服务器支持 Gzip 解压。

  5. 代码分割:

    除了提取公共资源,我们还可以对代码进行更细粒度的分割。比如,可以把每个页面的组件都分割成单独的 chunk。

    Vue CLI 默认会对异步组件进行代码分割。如果你的组件不是异步组件,可以使用 import() 函数进行动态导入:

    // 异步组件
    const MyComponent = () => import('./MyComponent.vue');
    
    // 动态导入
    import('./MyComponent.vue').then(module => {
      const MyComponent = module.default;
    });

    使用动态导入的组件,会被分割成单独的 chunk。

  6. 路由懒加载:

    如果你的 MPA 项目里,某个页面比较大,可以使用路由懒加载,只有当用户访问这个页面的时候才加载。

    在 Vue Router 里,使用 import() 函数进行动态导入:

    const routes = [
      {
        path: '/about',
        component: () => import('./pages/about/App.vue')
      }
    ];

    这样,只有当用户访问 /about 页面的时候,才会加载 about 页面的组件。

  7. 缓存:

    利用浏览器缓存可以有效减少资源加载时间。可以设置 HTTP 缓存头,例如 Cache-ControlExpires,来控制浏览器缓存行为。 对于静态资源,可以设置较长的缓存时间,对于动态资源,可以设置较短的缓存时间或者使用 ETagLast-Modified 来进行缓存验证。

    此外,还可以使用 Service Worker 来实现更高级的缓存策略,例如离线访问。

第三章:MPA 项目的坑:小心别踩雷!

MPA 项目虽然简单,但是也有一些坑需要注意。

  1. publicPath 配置:

    如果你的 MPA 项目部署在子目录下,比如 https://example.com/my-app/,你需要配置 publicPath,否则资源路径会出错。

    vue.config.js 里,配置 publicPath

    module.exports = {
      publicPath: '/my-app/'
    };
  2. 跨域问题:

    如果你的 MPA 项目需要访问其他域名的 API,可能会遇到跨域问题。

    解决跨域问题的方法有很多,比如 JSONP、CORS、代理等等。

    在 Vue CLI 里,可以使用 devServer.proxy 配置代理:

    module.exports = {
      devServer: {
        proxy: {
          '/api': {
            target: 'http://api.example.com',
            changeOrigin: true,
            pathRewrite: {
              '^/api': ''
            }
          }
        }
      }
    };

    这样,所有以 /api 开头的请求都会被代理到 http://api.example.com

  3. 页面间通信:

    MPA 项目里,每个页面都是独立的,页面间通信比较麻烦。

    常用的页面间通信方法有:

    • URL 参数: 通过 URL 参数传递数据。
    • localStorage 使用 localStorage 存储数据。
    • postMessage 使用 postMessage API 进行跨域通信。
    • Vuex: 如果你的项目比较复杂,可以使用 Vuex 进行状态管理。

第四章:总结:MPA 项目的优势与劣势

咱们来总结一下 MPA 项目的优势和劣势:

优势 劣势
SEO 友好 页面切换可能会有白屏
首屏加载快 公共资源不好管理
每个页面都是独立的,易于维护 页面间通信比较麻烦
适合简单的、静态的网站 不适合复杂的、交互性强的网站
可以使用不同的技术栈来构建不同的页面 构建过程可能比 SPA 复杂,需要更多配置

尾声:选择适合你的才是最好的!

好了,今天的讲座就到这里了。希望大家对 Vue CLI MPA 项目有了更深入的了解。记住,没有最好的技术,只有最适合你的技术。选择 SPA 还是 MPA,要根据你的项目实际情况来决定。

如果大家还有什么问题,欢迎随时提问。祝大家编程愉快! Bye Bye!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注