Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

建议官网展示的前端项目nginx部署的时候加上gzip压缩,加速第一次访问 #88

Closed
ileadall42 opened this issue May 1, 2019 · 17 comments

Comments

@ileadall42
Copy link

ileadall42 commented May 1, 2019

nginx.conf 的 http 中加入 # gzip config片断

具体参数:

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    # gzip config
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 9;
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";

server {
    listen 80;
    root /usr/share/nginx/html;

    location / {
        # 用于配合 browserHistory使用
        try_files $uri $uri/ /index.html;

        # 如果有资源,建议使用 https + http2,配合按需加载可以获得更好的体验
        # rewrite ^/(.*)$ https://preview.pro.ant.design/$1 permanent;

    }
    location /api {
        proxy_pass https://preview.pro.ant.design;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   Host              $http_host;
        proxy_set_header   X-Real-IP         $remote_addr;
    }
}

参考:在部署的时候开启nginx的gzip自己调节参数,以及history的try_files解决方案和相关https安全部署方案。

@zhangdaiscott
Copy link
Member

3q

@wanrengang
Copy link

如何实现按需加载对应的文件 目前是一次性全部加载

@shuperry
Copy link

@ileadall42 你好,我用的是 caddy,也加了 gzip 相关的配置,第一次访问速度还是在 5 到 6 秒才能打开页面,去琢磨了下代码里面,优化空间确实不大了,这个速度算正常吗,咨询下你那边是多长时间,还有别的优化建议吗

@shuperry
Copy link

办法是有,在 vue.config.js 里面加上压缩的代码,在 nginx.conf 里面加上 gzip,我自己弄了,需要参考代码不

@jlsunl
Copy link

jlsunl commented Jun 18, 2020

办法是有,在 vue.config.js 里面加上压缩的代码,在 nginx.conf 里面加上 gzip,我自己弄了,需要参考代码不

配置发一下,参考一下吧

@shuperry
Copy link

shuperry commented Jun 19, 2020

@jlsunl 项目整体需要把 ant-design-vue 改成按需加载

nginx.conf 的 http 中加入以下片断

  gzip              on;
  gzip_disable      "MSIE [1-6]\.";
  gzip_static       on;
  gzip_proxied      any;
  gzip_min_length   1k;
  gzip_comp_level   5;
  gzip_buffers      4 16k;
  gzip_types        text/plain text/javascript text/css text/xml application/javascript application/x-javascript application/xml application/json application/xml+rss image/jpeg image/gif image/png;
  gzip_vary         off;
  gzip_http_version 1.0;

vue.config.js

const path = require('path')

const TerserWebpackPlugin = require('terser-webpack-plugin')
const CompressionWebpackPlugin = require('compression-webpack-plugin')

const keys = require('lodash.keys')
const os = require('os')
const webpack = require('webpack')

const createThemeColorReplacerPlugin = require('./plugins/theme.plugin')

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

const envConfig = require('./src/config/env.config')

const isOnline = !['local'].includes(process.env.mode)
const isProduction = ['prod'].includes(process.env.mode)

const assetsCDN = {
  // webpack build externals
  externals: {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    vuex: 'Vuex',
    axios: 'axios'
  },
  css: [],
  js: [
    '//cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
    '//cdn.jsdelivr.net/npm/vue-router@3.1.6/dist/vue-router.min.js',
    '//cdn.jsdelivr.net/npm/vuex@3.3.0/dist/vuex.min.js',
    '//cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js'
  ]
}

const productionGzipExtensions = ['js', 'css', 'json', 'txt', 'html', 'ico', 'svg']

// vue.config.js
const vueConfig = {
  configureWebpack: config => {
    // webpack plugins
    config.plugins.push(
      // Ignore all locale files of moment.js
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
      createThemeColorReplacerPlugin()
    )

    if (isOnline) {
      config.plugins.push(
        // 开启压缩
        new CompressionWebpackPlugin({
          filename: '[path].gz[query]',
          algorithm: 'gzip',
          test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
          threshold: 10240,
          minRatio: 0.8
        }),
        new TerserWebpackPlugin({
          sourceMap: false,
          parallel: false,
          terserOptions: {
            compress: {
              drop_debugger: isProduction,
              drop_console: isProduction,
              pure_funcs: [] // 移除console
            },
            beautify: false,
            comments: false,
            keep_classnames: false,
            output: {
              comments: false,
            }
          }
        })
      )

      config.performance = {
        hints: 'warning',
        // 入口起点的最大体积 整数类型(以字节为单位 500k).
        maxEntrypointSize: 500 * 1024,
        // 生成文件的最大体积 整数类型(以字节为单位 300k).
        maxAssetSize: 300 * 1024,
        // 只给出 js 文件的性能提示.
        assetFilter: function(assetFilename) {
          return assetFilename.endsWith('.js')
        }
      }
    }

    // if prod, add externals
    config.externals = isOnline ? assetsCDN.externals : {}
  },

  chainWebpack: (config) => {
    config.resolve.alias
      .set('@$', resolve('src'))

    const svgRule = config.module.rule('svg')
    svgRule.uses.clear()
    svgRule
      .oneOf('inline')
      .resourceQuery(/inline/)
      .use('vue-svg-icon-loader')
      .loader('vue-svg-icon-loader')
      .end()
      .end()
      .oneOf('external')
      .use('file-loader')
      .loader('file-loader')
      .options({
        name: 'assets/[name].[hash:8].[ext]'
      })

    config.plugin('define').tap(args => {
      keys(envConfig[process.env.mode]).forEach(key => {
        args[0]['process.env'][key] = JSON.stringify(envConfig[process.env.mode][key])
      })
      return args
    })

    if (isOnline) {
      // 删除预加载
      config.plugins.delete('preload')
      config.plugins.delete('prefetch')

      config.output.filename('[name].[hash].js').end()

      config.plugin('html').tap(args => {
        args[0].cdn = assetsCDN
        return args
      })
    }
  },

  css: {
    sourceMap: false,
    loaderOptions: {
      less: {
        lessOptions: {
          modifyVars: {
            // less vars,customize ant design theme

            // 'primary-color': '#F5222D',
            // 'link-color': '#F5222D',
            'border-radius-base': '2px'
          },
          // DO NOT REMOVE THIS LINE
          javascriptEnabled: true
        }
      }
    }
  },

  devServer: {
    // development server port 3000
    port: 3000,
    proxy: {
      '/api2': {
        target: envConfig[process.env.mode].BASE_API_2, // 请求本地需要后台项目
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '/api2': '' // 默认所有请求都加了 api 前缀, 需要去掉
        }
      },
      '/api': {
        target: envConfig[process.env.mode].BASE_API, // 请求本地需要后台项目
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '/api': '' // 默认所有请求都加了 api 前缀, 需要去掉
        }
      }
    }
  },
  parallel: os.cpus().length > 1,
  // 如果你不需要生产环境的 source map, 可以将其设置为 false 以加速生产环境构建.
  productionSourceMap: false,
  lintOnSave: false,
  // babel-loader no-ignore node_modules/*
  transpileDependencies: ['vue-plyr']
}

module.exports = vueConfig

@zhangdaiscott
Copy link
Member

#1343

@jwcjf
Copy link

jwcjf commented Jun 28, 2020

@jlsunl 项目整体需要把 ant-design-vue 改成按需加载

nginx.conf 的 http 中加入以下片断

  gzip              on;
  gzip_disable      "MSIE [1-6]\.";
  gzip_static       on;
  gzip_proxied      any;
  gzip_min_length   1k;
  gzip_comp_level   5;
  gzip_buffers      4 16k;
  gzip_types        text/plain text/javascript text/css text/xml application/javascript application/x-javascript application/xml application/json application/xml+rss image/jpeg image/gif image/png;
  gzip_vary         off;
  gzip_http_version 1.0;

vue.config.js

const path = require('path')

const TerserWebpackPlugin = require('terser-webpack-plugin')
const CompressionWebpackPlugin = require('compression-webpack-plugin')

const keys = require('lodash.keys')
const os = require('os')
const webpack = require('webpack')

const createThemeColorReplacerPlugin = require('./plugins/theme.plugin')

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

const envConfig = require('./src/config/env.config')

const isOnline = !['local'].includes(process.env.mode)
const isProduction = ['prod'].includes(process.env.mode)

const assetsCDN = {
  // webpack build externals
  externals: {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    vuex: 'Vuex',
    axios: 'axios'
  },
  css: [],
  js: [
    '//cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
    '//cdn.jsdelivr.net/npm/vue-router@3.1.6/dist/vue-router.min.js',
    '//cdn.jsdelivr.net/npm/vuex@3.3.0/dist/vuex.min.js',
    '//cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js'
  ]
}

const productionGzipExtensions = ['js', 'css', 'json', 'txt', 'html', 'ico', 'svg']

// vue.config.js
const vueConfig = {
  configureWebpack: config => {
    // webpack plugins
    config.plugins.push(
      // Ignore all locale files of moment.js
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
      createThemeColorReplacerPlugin()
    )

    if (isOnline) {
      config.plugins.push(
        // 开启压缩
        new CompressionWebpackPlugin({
          filename: '[path].gz[query]',
          algorithm: 'gzip',
          test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
          threshold: 10240,
          minRatio: 0.8
        }),
        new TerserWebpackPlugin({
          sourceMap: false,
          parallel: false,
          terserOptions: {
            compress: {
              drop_debugger: isProduction,
              drop_console: isProduction,
              pure_funcs: [] // 移除console
            },
            beautify: false,
            comments: false,
            keep_classnames: false,
            output: {
              comments: false,
            }
          }
        })
      )

      config.performance = {
        hints: 'warning',
        // 入口起点的最大体积 整数类型(以字节为单位 500k).
        maxEntrypointSize: 500 * 1024,
        // 生成文件的最大体积 整数类型(以字节为单位 300k).
        maxAssetSize: 300 * 1024,
        // 只给出 js 文件的性能提示.
        assetFilter: function(assetFilename) {
          return assetFilename.endsWith('.js')
        }
      }
    }

    // if prod, add externals
    config.externals = isOnline ? assetsCDN.externals : {}
  },

  chainWebpack: (config) => {
    config.resolve.alias
      .set('@$', resolve('src'))

    const svgRule = config.module.rule('svg')
    svgRule.uses.clear()
    svgRule
      .oneOf('inline')
      .resourceQuery(/inline/)
      .use('vue-svg-icon-loader')
      .loader('vue-svg-icon-loader')
      .end()
      .end()
      .oneOf('external')
      .use('file-loader')
      .loader('file-loader')
      .options({
        name: 'assets/[name].[hash:8].[ext]'
      })

    config.plugin('define').tap(args => {
      keys(envConfig[process.env.mode]).forEach(key => {
        args[0]['process.env'][key] = JSON.stringify(envConfig[process.env.mode][key])
      })
      return args
    })

    if (isOnline) {
      // 删除预加载
      config.plugins.delete('preload')
      config.plugins.delete('prefetch')

      config.output.filename('[name].[hash].js').end()

      config.plugin('html').tap(args => {
        args[0].cdn = assetsCDN
        return args
      })
    }
  },

  css: {
    sourceMap: false,
    loaderOptions: {
      less: {
        lessOptions: {
          modifyVars: {
            // less vars,customize ant design theme

            // 'primary-color': '#F5222D',
            // 'link-color': '#F5222D',
            'border-radius-base': '2px'
          },
          // DO NOT REMOVE THIS LINE
          javascriptEnabled: true
        }
      }
    }
  },

  devServer: {
    // development server port 3000
    port: 3000,
    proxy: {
      '/api2': {
        target: envConfig[process.env.mode].BASE_API_2, // 请求本地需要后台项目
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '/api2': '' // 默认所有请求都加了 api 前缀, 需要去掉
        }
      },
      '/api': {
        target: envConfig[process.env.mode].BASE_API, // 请求本地需要后台项目
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '/api': '' // 默认所有请求都加了 api 前缀, 需要去掉
        }
      }
    }
  },
  parallel: os.cpus().length > 1,
  // 如果你不需要生产环境的 source map, 可以将其设置为 false 以加速生产环境构建.
  productionSourceMap: false,
  lintOnSave: false,
  // babel-loader no-ignore node_modules/*
  transpileDependencies: ['vue-plyr']
}

module.exports = vueConfig

请问相关require文件能发一下吗谢谢

@jlsunl
Copy link

jlsunl commented Jun 28, 2020

@shuperry 谢谢

@wyyina
Copy link

wyyina commented Jul 15, 2020

plugins/theme.plugin? 在哪里 谢谢

@wyyina
Copy link

wyyina commented Jul 15, 2020

大佬 env.config 也发下啊

@shuperry
Copy link

@wyyina plugins/theme.plugin.js

const ThemeColorReplacer = require('webpack-theme-color-replacer')
const generate = require('@ant-design/colors/lib/generate').default

const getAntdSerials = (color) => {
  // 淡化(即less的tint)
  const lightens = new Array(9).fill().map((t, i) => {
    return ThemeColorReplacer.varyColor.lighten(color, i / 10)
  })
  const colorPalettes = generate(color)
  const rgb = ThemeColorReplacer.varyColor.toNum3(color.replace('#', '')).join(',')
  return lightens.concat(colorPalettes).concat(rgb)
}

const themePluginOption = {
  fileName: 'css/theme-colors-[contenthash:8].css',
  matchColors: getAntdSerials('#1890ff'), // 主色系列
  // 改变样式选择器,解决样式覆盖问题
  changeSelector (selector) {
    switch (selector) {
      case '.ant-calendar-today .ant-calendar-date':
        return ':not(.ant-calendar-selected-date):not(.ant-calendar-selected-day)' + selector
      case '.ant-btn:focus,.ant-btn:hover':
        return '.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger)'
      case '.ant-btn.active,.ant-btn:active':
        return '.ant-btn.active:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:active:not(.ant-btn-primary):not(.ant-btn-danger)'
      case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
      case '.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon':
        return ':not(.ant-steps-item-process)' + selector
      // fixed https://github.com/vueComponent/ant-design-vue-pro/issues/876
      case '.ant-steps-item-process .ant-steps-item-icon':
        return ':not(.ant-steps-item-custom)' + selector
      case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
      case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
        return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover'
      case '.ant-menu-horizontal > .ant-menu-item-selected > a':
      case '.ant-menu-horizontal>.ant-menu-item-selected>a':
        return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item-selected > a'
      case '.ant-menu-horizontal > .ant-menu-item > a:hover':
      case '.ant-menu-horizontal>.ant-menu-item>a:hover':
        return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item > a:hover'
      default :
        return selector
    }
  }
}

const createThemeColorReplacerPlugin = () => new ThemeColorReplacer(themePluginOption)

module.exports = createThemeColorReplacerPlugin

env.config.js

module.exports = {
  local: {
    BASE_API: 'xxx'
  },
  dev: {
    BASE_API: 'xxx'
  },
  sit: {
    BASE_API: 'xxx'
  },
  prod: {
    BASE_API: 'xxx',
  }
}

package.json -> scripts

"scripts": {
    "start": "cross-env mode=local vue-cli-service serve --open --mode local",
    "build:dev": "cross-env mode=dev vue-cli-service build",
    "build:sit": "cross-env mode=sit vue-cli-service build",
    "build:prod": "cross-env mode=prod vue-cli-service build"
  }

@jeecgboot jeecgboot deleted a comment from wuchangrong Aug 12, 2020
@jeecgboot jeecgboot deleted a comment from fangyueben Aug 12, 2020
@JaneYork
Copy link

访问速度很慢 #943

我也开启了GZIP,原来6M,后来2M,但是首次加载30秒???
还有其他方式吗

@zhangdaiscott
Copy link
Member

第一次就是慢点,等vue3出来,会显著改善

@CondiGao
Copy link

vue3也没快多少

@wuchangrong
Copy link

vue3也没快多少

是的,没有感觉到vue3快过

@jeecgboot jeecgboot deleted a comment from shuperry Apr 18, 2023
@zhangdaiscott
Copy link
Member

zhangdaiscott commented Apr 18, 2023

部署之后比vue2现住快很多,开发环境的确不如vue2

lexmeng pushed a commit to lexmeng/jeecg-boot that referenced this issue Jun 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants