项目难点和优化

难点: 对于同一个位置百度地图定位的经纬度和腾讯地图定位的经纬度不一样?

解决:由于两者所用的算法不同,计算出来的经纬度也是不一样的,将百度地图的经纬度转换成腾讯地图的经纬度/腾讯的经纬度转化百度的经纬度
export function  bMapTransQQMap(lng,lat){
        let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        let x = lng - 0.0065;
        let y = lat - 0.006;
        let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
        let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
        let lngs = z * Math.cos(theta);
        let lats = z * Math.sin(theta);
        return {
            longitude: lngs,
            latitude: lats
        }
 }
// 腾讯转百度
export function qqMapTransBMap(lng,lat){
        let x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        let x = lng;
        let y = lat;
        let z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
        let theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
        let lngs = z * Math.cos(theta) + 0.0065;
        let lats = z * Math.sin(theta) + 0.006;
        return {
            longitude: lngs,
            latitude: lats
        }
}

难点 : 移动端使用echarts绘制图表使用tooltip无效果

解决:

echarts 引入的时候,会优先判断当前的环境。

uniapp的又一个全局变量就叫做wx。
导致这里的判断直接走第一个。

在main.js中

window.wx = {}  直接将wx重新赋值。

难点:echarts中的面积图,由于点击区域、折线、折线中的小圆点都会出现提示框,只有点击折线上的点才出现tooltip(提示框),

解决:通过监听echart的鼠标的mouseover事件,函数中设置某个全局变量为当前折线的seriesName(名字),然后再监听鼠标的mouseout事件,函数中设置某个全局变量为空字符串,这两个事件只有直线上的小圆点才执行的,所以可以区分区域点击事件和折线点击事件,之后在提示框的自定义内容中(formatter),如果存在某个全局变量就显示提示框,否则不显示。

难点:在线上,使用window.open方法无法实现下载功能

解决:

webpack构建优化

优化策略

既然我们已经找到了拉低我们构建速率的“罪魁祸首”,接下来我们就点对点逐个击破了!这里,我就直接开门见山了,既然我们都知道构建耗时的原因,自然就能得出针对性的方略。所以我们会从四个大方向入手:缓存、多核、抽离以及拆分,你现在看到这四个词或许脑海里又能浮现出了一些熟悉的思路,这很棒,这样的话你对我接下来将介绍的手段一定就能更快理解。

  • 初始打包速度

    242s

  • 第二次打包速度

    97s

  • 初始编译速度

    165s

  • 第二次编译速度

    76s

    开始优化 ✈︎

    1、externals 提取项目依赖

    从上面的打包分析页面中可以看到,chunk-vendors.js 体积为 2.21M,其中最大的几个文件都是一些公共依赖包,那么只要把这些依赖提取出来,就可以解决 chunk-vendors.js 过大的问题

    可以使用 externals 来提取这些依赖包,告诉 webpack 这些依赖是外部环境提供的,在打包时可以忽略它们,就不会再打到 chunk-vendors.js 中

    1)vue.config.js 中配置:

    module.exports = {
      configureWebpack: {
        externals: {
          vue: 'Vue',
          'vue-router': 'VueRouter',
          axios: 'axios',
          echarts: 'echarts'
        }
    }
    复制代码
    
      configureWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
          //生产环境取消 console.log
          config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
          // 不打包 tinymce
          config.externals = {
            tinymce: 'tinymce',
            'tinymce-vue': 'tinymceVue',
            'vue-baidu-map': 'vueBaiduMap',
            vue: 'Vue',
            'vue-router': 'VueRouter',
            axios: 'axios',
            echarts: 'echarts',
       		"vxe-table": "vxeTable",
              "vxe-table-plugin-antd": "vxeTablePluginAntd",
              "xe-utils": "xeUtils",
              "moment-timezone": "momentTimezone",
              "antv":"antv",
              "@antv":"@antv",
              "ant-design": "antDesign",
              "@ant-design": "@antDesign"
          }
        }
     }
    

    cdn可能会断开链接,同时存在不安全的隐患

    2)在 index.html 中使用 CDN 引入依赖

      
        
        
        
        
      
    复制代码
    

    验证 externals 的有效性:

    重新打包,最新数据如下:92s

    include 和exclude 缩小范围

     chainWebpack: (config) => {
        // 配置 webpack 识别 markdown 为普通的文件
        config.module
          .rule('markdown')
          .test(/\.md$/)
          .use()
          .loader('file-loader')
          .end()
      }
    

    alias 别名设置搜索查找范围

     chainWebpack: (config) => {
         config.resolve.alias
          .set('@$', resolve('src'))
          .set('@api', resolve('src/api'))
          .set('@assets', resolve('src/assets'))
          .set('@comp', resolve('src/components'))
          .set('@views', resolve('src/views'))
      }
    

    使用绝对路径指明第三方模块存放的位置,以减少搜索步骤

    缩小查找后缀文件的范围

    noParse、extensions、modules

      configureWebpack: config => {
        //生产环境取消 console.log
        if (process.env.NODE_ENV === 'production') {
          config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
          config.externals = {
            tinymce: 'tinymce',
            'tinymce-vue': 'tinymceVue',
            'vue-baidu-map': 'vueBaiduMap',
            vue: 'Vue',
            'vue-router': 'VueRouter',
            axios: 'axios',
            echarts: 'echarts'
          }
        }
        // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
        // __diename 表示当前工作目录,也就是项目根目录
        config.resolve.modules.unshift(resolve('node_modules'))
        // 缩小查找后缀文件的范围
        config.resolve.extensions = ['.vue', '.js', '.json']
        // 防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 
        // 不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。
        config.module.noParse = /^(vue|vue-router|vuex|vuex-router-sync|jquery|lodash|chartjs|echarts|axios)$/
        config.plugins.push(new ProgressBarPlugin({
          format: `  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
        }))
      },
    

    减少第三方库的体积

    按需加载第三方库,减少代码体积

    echarts按需加载文件

    @/utils/echarts.js

    // 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
    import * as echarts from 'echarts/core';
    import 'echarts/lib/component/legend'
     
    // 引入柱状图图表,图表后缀都为 Chart
    // 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
    import {
        TitleComponent,
        TooltipComponent,
        GridComponent,
        DatasetComponent,
        TransformComponent
    } from 'echarts/components';
    // 标签自动布局、全局过渡动画等特性
    import {LabelLayout, UniversalTransition} from 'echarts/features';
    // 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
    import {CanvasRenderer} from 'echarts/renderers';
     
    // **引入组件 都是以Chart结尾 关键 我这里只用到了折线图, 如果要引入饼状图 PieChart
    import {LineChart, BarChart, PieChart, TreemapChart, FunnelChart} from 'echarts/charts';
     
     
    // 注册必须的组件
    echarts.use([
        TitleComponent,
        TooltipComponent,
        GridComponent,
        DatasetComponent,
        TransformComponent,
        LineChart,
        TreemapChart,
        FunnelChart,
        BarChart,
        PieChart,
        LabelLayout,
        UniversalTransition,
        CanvasRenderer
    ]);
     
    export default echarts
    
    

    使用:import echarts from ‘@/utils/Echarts’

    moment

    使用 moment-locales-webpack-plugin 插件,剔除掉无用的语言包

    1)安装

    npm install moment-locales-webpack-plugin -D
    复制代码
    

    2)vue.config.js 中引入

    const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
    
    configureWebpack: config => {
        config.plugins.push(new ProgressBarPlugin({
          format: `  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
        }), new MomentLocalesPlugin({ localesToKeep: ['zh-cn'] }))
      },
    复制代码
    

    验证插件的有效性:

    压缩js、css,gzip压缩

    npm i compression-webpack-plugin -D
    
    const CompressionPlugin = require("compression-webpack-plugin")
    
    chainWebpack: (config) => { 
          //生产环境,开启js\css压缩
        if (process.env.NODE_ENV === 'production') {
          config.plugin('compressionPlugin').use(
            new CompressionPlugin({
                test: /\.(js|css|html)$/, // 匹配文件名
                filename: '[path].gz[query]', // 压缩后的文件名
                algorithm: 'gzip', // 使用gzip压缩
                minRatio: 1, // 压缩率小于1才会压缩
                threshold: 10240,
                deleteOriginalAssets: false //是否删除原文件
            })
        )
            // config.plugin('compressionPlugin').use(new CompressionPlugin({
            //   test: /\.(js|css|less)$/, // 匹配文件名
            //   threshold: 10240, // 对超过10k的数据压缩
            //   deleteOriginalAssets: false // 不删除源文件
            // }))
        }
      } 
    
    • 初始打包速度

      82s

    • 初始编译速度

      144s

    • 第二次编译速度

      63s

webpack构建优化

构建前: 编译速度:2.69m

​ 构建速度 :第一次构建速度: 59.93,

​ cache-loader: 默认脚手架使用了cache-loader进行缓存,第二次的构建速度: 39.84 ,构建速度提升了33%

​ 为 loader 指定 include,减少 loader 应用范围,仅应用于最少数量的必要模块,。rule.exclude 可以排除模块范围,也可用于减少 loader 应用范围.

​ thread-loader多线程:

项目难点和优化_第1张图片

第一次编译:177 第二次编译: 75 热更新:15

在优化开始之前,需要做一些准备工作。

安装以下 webpack 插件,帮助我们分析优化效率:

1. 编译进度条

一般来说,中型项目的首次编译时间为 5-20s,没个进度条等得多着急,通过 progress-bar-webpack-plugin 插件查看编译进度,方便我们掌握编译情况。

安装:

npm i -D progress-bar-webpack-plugin

vue.config.js 配置如下

const chalk = require('chalk')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
 configureWebpack: config => {
      config.plugins.push(new ProgressBarPlugin({
      format: `  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
    }))
 }

2. 编译速度分析

优化 webpack 构建速度,首先需要知道是哪些插件、哪些 loader 耗时长,方便我们针对性的优化。

通过 speed-measure-webpack-plugin 插件进行构建速度分析,可以看到各个 loader、plugin 的构建时长,后续可针对耗时 loader、plugin 进行优化。

安装:

npm i -D speed-measure-webpack-plugin

vue.config.js 配置如下

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
 configureWebpack: config => {
      config.plugins.push(new ProgressBarPlugin({
      format: `  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
    }), new SpeedMeasurePlugin())
 }

3. 打包体积分析

build 构建打包命令加入 --report inspect命令生成一份vue-cli 内置的配置内容

  "scripts": {
    "build": "vue-cli-service build --report",
    "inspect": "vue-cli-service inspect --> output.js"
  },

4. 查看vue.config.js 的输出后的所有配置

  "scripts": {
    "inspect": "vue-cli-service inspect --> output.js"
  },

第一次编译:219s ,第二次编译:72s

加入配置config.resolve.modules 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤 extensions缩小查找后缀的范围

 configureWebpack: config => {
      // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
    // __diename 表示当前工作目录,也就是项目根目录
    config.resolve.modules.unshift(resolve('node_modules'))
    config.resolve.extensions = ['.js', '.vue', '.json']
  },

构建完成:第一次编译:173s 153s 第二次编译:65s

加入配置 **config.module.noParse = /^(vue|vue-router|vuex|vuex-router-sync|jquery|lodash|chartjs|echarts)$/ ** 防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。

 configureWebpack: config => {
        // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
    // __diename 表示当前工作目录,也就是项目根目录
    config.resolve.modules.unshift(resolve('node_modules'))
    config.resolve.extensions = ['.js', '.vue', '.json']
     // 防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 
    // 不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。
    config.module.noParse = /^(vue|vue-router|vuex|vuex-router-sync|lodash)$/
  },

构建完成:第一次编译:155s 第二次编译:64

加入thread-loader —— 开启多线程优化配置,对于编译时间过长的loader加入thread-loader,

注意:仅在耗时的操作中使用 thread-loader,否则使用 thread-loader 会后可能会导致项目构建时间变得更长,因为每个 worker 都是一个独立的 node.js 进程,其开销大约为 600ms 左右,同时还会限制跨进程的数据交换等。

 configureWebpack: config => {
      // 对babel-loader 使用thread-loader
    config.module.rules[12].use.unshift({
      loader: 'thread-loader',
      options: {
        workers: 3 // 进程3个
      }
    })
    config.module.rules[15].use.unshift({
      loader: 'thread-loader',
      options: {
        workers: 3 // 进程3个
      }
    })
 }
  chainWebpack: config => { 
  	 config.module
      .rule('markdown')
      .test(/\.md$/)
      .use('loader1')
        .loader('loader1') // 第一个 Loader
        .end()
      .use('loader2')
        .loader('loader2') // 第二个 Loader
        .options({ /* Loader 的选项 */ })
        .end()
      .use('loader3')
        .loader('loader3') // 第三个 Loader
        .end();
  }

构建完成:第一次编译:151s 第二次编译:62s

IgnorePlugin

webpack 的内置插件,作用是忽略第三方包指定目录。

例如: moment (2.24.0版本) 会将所有本地化内容和核心功能一起打包,我们就可以使用 IgnorePlugin 在打包时忽略本地化内容。

//webpack.config.js
module.exports = {
    //...
    plugins: [
        //忽略 moment 下的 ./locale 目录
        new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
    ]
}

在使用的时候,如果我们需要指定语言,那么需要我们手动的去引入语言包,例如,引入中文语言包:

import moment from 'moment';
import 'moment/locale/zh-cn';// 手动引入

index.js 中只引入 moment,打包出来的 bundle.js 大小为 263KB,如果配置了 IgnorePlugin,单独引入 moment/locale/zh-cn,构建出来的包大小为 55KB

externals

我们可以将一些JS文件存储在 CDN 上(减少 Webpack打包出来的 js 体积),在 index.html 中通过

你可能感兴趣的:(dubbo)