Vue typescript 如何极限压缩编译静态资源

2022-07-25 17:02:23 浏览数 (1)

# Vue typescript 如何极限压缩编译后静态资源

# 前言

近期开发项目,由于资源有限,云服务器只有1m带宽。 vue初始打包的静态资源,通过浏览器加载需要近1分钟的时间。 所以需要将静态资源进行压缩及相应处理,最终浏览器访问时间为5秒钟

# 一、安装依赖

首先安装依赖 compression-webpack-plugin image-webpack-loader

  • yarn
代码语言:javascript复制
yarn add compression-webpack-plugin -D
yarn add image-webpack-loader -D
  • npm
代码语言:javascript复制
npm install compression-webpack-plugin --save-dev
npm install image-webpack-loader --save-dev

注意

记住,依赖一定要安装在 devDependencies 下,否则会增大你的打包体积

# 二、压缩图片

提示

图片处理其实有很多种方式,例如引入cdn服务器等。

此处介绍的方式为,需要将图片和静态资源打包在一起时的解决方案。

# 1. 处理图片

  • 首先需要对图片进行处理,处理方式自行选择,例如使用ps将图片质量减小等。
  • 此处推荐一个在线压缩图片,处理图片的网站https://imagecompressor.com/zh/

注意

不保证网站是否会收集图片数据,如果数据较为敏感,请不要上传,自行进行处理。

此步骤主要是为了将原始图片进一步压缩。

# 2. 打开vue.config.js 文件

打开vue的配置文件

# 3. 编写压缩图片配置

需要在文件中编写相应的压缩,可以对图片进行二次压缩。请根据需求自行配置。 详细使用说明可参考 https://www.npmjs.com/package/image-webpack-loader

代码语言:javascript复制
module.exports = {
  // 省略部分配置项
  ....
  ,
  chainWebpack: config => {
    // 省略部分配置项
    ...
    // 判断环境不为开发环境
    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
      		// 压缩图片配置
          config.module
            .rule('images')
            .use('image-webpack-loader')
            .loader('image-webpack-loader')
            .options({
              mozjpeg: { progressive: true, quality: 65 }, // Compress JPEG images
              optipng: { enabled: false }, // Compress PNG images
              pngquant: { quality: [0.65, 0.9], speed: 4 }, // Compress PNG images
              gifsicle: { interlaced: false } // Compress SVG images
            })
            .end()
        }
     )
  }
}

# 三、压缩资源

# 1. 打开vue.config.js 文件

打开vue的配置文件

# 2. 编写压缩配置

配置压缩资源,具体配置项可参考https://www.npmjs.com/package/compression-webpack-plugin

代码语言:javascript复制
// 引入压缩依赖
const CompressionPlugin = require('compression-webpack-plugin')
// 需要压缩的文件的正则
const productionGzipExtensions = /.(js|css|json|txt|html|ico|svg)(?.*)?$/i

module.exports = {
 // 省略部分配置项
  ....
  ,
  chainWebpack: config => {  
    // 省略部分配置项
    ...
    // 判断环境不为开发环境
    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
          // 打包成gzip压缩文件
          config.plugin('compressionPlugin')
            .use(new CompressionPlugin({
              filename: '[path].gz[query]',
              algorithm: 'gzip',
              test: productionGzipExtensions,
              threshold: 10240,
              minRatio: 0.8,
              deleteOriginalAssets: true
            }))
        }
     )
  }
}

# 四、抽取公共代码打包

# 1. 打开vue.config.js 文件

打开vue的配置文件

# 2. 编写抽取公共代码配置

此处为将代码中的公共部分抽取出来,统一打包,可减小打包后的代码体积。

代码语言:javascript复制
module.exports = {
  // 省略部分配置项
  ....
  ,
  chainWebpack: config => {
    // 省略部分配置项
    ...
    // 判断环境不为开发环境
    config
      .when(process.env.NODE_ENV !== 'development',        
          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: path.resolve(__dirname, 'src/components'),
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true
                }
              }
            })
          config.optimization.runtimeChunk('single')
        }
      )
  }
}

# 五、引用CDN

注意

此处引用的js和css的公共cdn代码库。

引入cdn后可有效减少从服务获取的资源数量。

但是有风险,一旦cdn服务出问题,你的网站也将无法访问。

此步骤请谨慎选择或使用自己的cdn服务器。

# 1. 打开vue.config.js 文件

打开vue的配置文件

# 2. 配置CDN

代码语言:javascript复制
const cdn = {
  css: [
    'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/theme-chalk/index.min.css',
    'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css'
  ],
  js: [
    // vue必须在第一个
    'https://cdn.bootcss.com/vue/2.6.11/vue.min.js',
    'https://cdn.bootcss.com/vuex/3.2.0/vuex.min.js',
    'https://cdn.bootcss.com/vue-router/3.4.3/vue-router.min.js',
    'https://cdn.bootcss.com/axios/0.19.2/axios.min.js',
    'https://cdn.bootcss.com/qs/6.5.1/qs.min.js',
    'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/index.min.js',
    'https://cdn.bootcdn.net/ajax/libs/echarts/4.7.0/echarts-en.min.js',
    'https://cdn.bootcdn.net/ajax/libs/dexie/3.0.3/dexie.min.js',
    'https://cdn.bootcdn.net/ajax/libs/js-cookie/2.2.1/js.cookie.min.js',
    'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js'
  ]
}

module.exports = {
   // 省略部分配置项
  ....
  ,
  chainWebpack: config => {    
    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
      		// 设置不打包的依赖,请根据自己需求进行修改
          const externals = {
            vue: 'Vue',
            vuex: 'Vuex',
            'vue-router': 'VueRouter',
            axios: 'axios',
            qs: 'Qs',
            'element-ui': 'ELEMENT',
            echarts: 'echarts',
            dexie: 'Dexie',
            'js-cookie': 'Cookies',
            nprogress: 'NProgress'
          }
          config.externals(externals)
          // 引入cdn
          config.plugin('html').tap(args => {
            args[0].cdn = cdn
            return args
          })
        }
      )
  }
}

# 六、配置Nginx

提示

如果你使用的ngxin服务器当做静态资源服务,则可以开启gzip配置。

开启后访问速度会获得极大的提升

代码语言:javascript复制
http {
		# 省略部分配置
    ...
    # 开启gzip
    gzip  on;

    gzip_static on;
    # 设置缓冲区大小
    gzip_buffers 4 16k;

    #压缩级别官网建议是6
    gzip_comp_level 6;
    #压缩的类型
    gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php;
    
    # 省略部分配置
    ...
}

# 七、完整的配置文件

代码语言:javascript复制
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const CompressionPlugin = require('compression-webpack-plugin')
const name = 'xxxx系统'
const productionGzipExtensions = /.(js|css|json|txt|html|ico|svg)(?.*)?$/i
const cdn = {
  css: [
    'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/theme-chalk/index.min.css',
    'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css'
  ],
  js: [
    // vue必须在第一个
    'https://cdn.bootcss.com/vue/2.6.11/vue.min.js',
    'https://cdn.bootcss.com/vuex/3.2.0/vuex.min.js',
    'https://cdn.bootcss.com/vue-router/3.4.3/vue-router.min.js',
    'https://cdn.bootcss.com/axios/0.19.2/axios.min.js',
    'https://cdn.bootcss.com/qs/6.5.1/qs.min.js',
    'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/index.min.js',
    'https://cdn.bootcdn.net/ajax/libs/echarts/4.7.0/echarts-en.min.js',
    'https://cdn.bootcdn.net/ajax/libs/dexie/3.0.3/dexie.min.js',
    'https://cdn.bootcdn.net/ajax/libs/js-cookie/2.2.1/js.cookie.min.js',
    'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js'
  ]
}

module.exports = {
  publicPath: './',
  outputDir: 'dist',
  // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。    资源放的目录
  assetsDir: './static',
  // 指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径    index的路劲和名字
  indexPath: './index.html',
  // publicPath: process.env.NODE_ENV === 'production' ? '/vue-typescript-admin-template/' : '/',
  lintOnSave: process.env.NODE_ENV === 'development',
  transpileDependencies: ['fuse.js', 'vuex-module-decorators', 'clipboard', 'markdown-it-vue'],
  productionSourceMap: false,
  devServer: {
    port: devServerPort,
    open: true,
    overlay: {
      warnings: false,
      errors: true
    },
    progress: false,
    proxy: {
      '/': {
        target: 'http://localhost:8082/',        
        withCredentials: true,
        changeOrigin: true, // needed for virtual hosted sites
        ws: true, // proxy websockets        
      }
    }
  },
  pwa: {
    name: name,
    workboxPluginMode: 'InjectManifest',
    workboxOptions: {
      swSrc: path.resolve(__dirname, 'src/pwa/service-worker.js')
    }
  },
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'scss',
      patterns: [
        path.resolve(__dirname, 'src/styles/_variables.scss'),
        path.resolve(__dirname, 'src/styles/_mixins.scss')
      ]
    }
  },
  chainWebpack: config => {
    // provide the app's title in webpack's name field, so that
    // it can be accessed in index.html to inject the correct title.
    config.set('name', name)    
    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
          config.module
            .rule('images')
            .use('image-webpack-loader')
            .loader('image-webpack-loader')
            .options({
              // { bypassOnDebug: true }
              mozjpeg: { progressive: true, quality: 65 }, // ∂Compress JPEG images
              optipng: { enabled: false }, // Compress PNG images
              pngquant: { quality: [0.65, 0.9], speed: 4 }, // Compress PNG images
              gifsicle: { interlaced: false } // Compress SVG images
              // webp: { quality: 75 }
            })
            .end()

          const externals = {
            vue: 'Vue',
            vuex: 'Vuex',
            'vue-router': 'VueRouter',
            axios: 'axios',
            qs: 'Qs',
            'element-ui': 'ELEMENT',
            echarts: 'echarts',
            dexie: 'Dexie',
            'js-cookie': 'Cookies',
            nprogress: 'NProgress'
          }
          config.externals(externals)
          // 引入cdn
          config.plugin('html').tap(args => {
            args[0].cdn = cdn
            return args
          })
          // 打包成gzip压缩文件
          config.plugin('compressionPlugin')
            .use(new CompressionPlugin({
              filename: '[path].gz[query]',
              algorithm: 'gzip',
              test: productionGzipExtensions,
              threshold: 10240,
              minRatio: 0.8,
              deleteOriginalAssets: true
            }))

          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: path.resolve(__dirname, 'src/components'),
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true
                }
              }
            })
          config.optimization.runtimeChunk('single')
        }
      )
  }
}

0 人点赞