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 引入的时候,会优先判断当前的环境。
uniapp的又一个全局变量就叫做wx。
导致这里的判断直接走第一个。
在main.js中
window.wx = {} 直接将wx重新赋值。
初始打包速度
97s
初始编译速度
165s
第二次编译速度
76s
从上面的打包分析页面中可以看到,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 引入依赖
<body>
<script src="http://lib.baomitu.com/vue/2.6.14/vue.min.js"></script>
<script src="http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js"></script>
<script src="http://lib.baomitu.com/axios/1.2.1/axios.min.js"></script>
<script src="http://lib.baomitu.com/echarts/5.3.2/echarts.min.js"></script>
</body>
复制代码
验证 externals 的有效性:
重新打包,最新数据如下:92s
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)`
}))
},
@/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-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'] }))
},
复制代码
验证插件的有效性:
初始打包速度
82s
初始编译速度
144s
第二次编译速度
63s
构建前: 编译速度:2.69m
? 构建速度 :第一次构建速度: 59.93,
? cache-loader: 默认脚手架使用了cache-loader进行缓存,第二次的构建速度: 39.84 ,构建速度提升了33%
? 为 loader 指定 include,减少 loader 应用范围,仅应用于最少数量的必要模块,。rule.exclude 可以排除模块范围,也可用于减少 loader 应用范围.
? thread-loader多线程:
第一次编译:177 第二次编译: 75 热更新:15
在优化开始之前,需要做一些准备工作。
安装以下 webpack 插件,帮助我们分析优化效率:
一般来说,中型项目的首次编译时间为 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)`
}))
}
优化 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())
}
build 构建打包命令加入 --report inspect命令生成一份vue-cli 内置的配置内容
"scripts": {
"build": "vue-cli-service build --report",
"inspect": "vue-cli-service inspect --> output.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
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
。
我们可以将一些JS文件存储在 CDN
上(减少 Webpack
打包出来的 js
体积),在 index.html
中通过 <script>
标签引入,如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root">root</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</body>
</html>
我们希望在使用时,仍然可以通过 import
的方式去引用(如 import $ from 'jquery'
),并且希望 webpack
不会对其进行打包,此时就可以配置 externals
。
//webpack.config.js
module.exports = {
//...
externals: {
//jquery通过script引入之后,全局中即有了 jQuery 变量
'jquery': 'jQuery'
}
}
构建完成: 226s 186s 代码体积减少50%,文件数量减少40%
性能分析工具:chrome-Lighthouse
分数:25
Eliminate render-blocking resources: 消除渲染阻塞资源
? 优化前:1.7s
? 优化后:0s
? 优化css样式:异步加载css:1、js动态加载css 2、rel=“preload”
<link type="text/css" rel="preload" href="<%= BASE_URL %>tinymce/skins/lightgray/skin.min.css"/>
? 优化js:babel-polyfill插件是开发环境才需要,不需要在生产环境上使用,去除掉babel-polyfill的引入,如需引入可异步加载js
splitChunk: 对代码进行分割,合并公用代码块,对第三方库分别独立打包,减少下载次数,合并零散的文件,减少http请求
压缩图片的体积
开启http2请求
开启gzip压缩
分数:57
const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')
function resolve(dir) {
return path.join(__dirname, dir)
}
// vue.config.js
module.exports = {
/*
Vue-cli3:
Crashed when using Webpack `import()` #2463
https://github.com/vuejs/vue-cli/issues/2463
*/
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false,
//qiankuan打包时放开
//outputDir: "../dist/main",
// 多入口配置
// pages: {
// index: {
// entry: 'src/main.js',
// template: 'public/index.html',
// filename: 'index.html',
// }
// },
//打包app时放开该配置
publicPath: '/health-archives-ui',
configureWebpack: config => {
//生产环境取消 console.log
// if (process.env.NODE_ENV === 'production') {
// config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
// }
config.optimization = {
splitChunks: {
chunks: 'all',
minSize: 0,
minChunks: 1,
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
chunks: 'all'
},
common: {
name: 'chunk-common',
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
chunks: 'all'
},
elementUI: {
name: 'chunk-elementUI',
priority: 20, // initial 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
chunks: 'all'
},
echarts: {
name: 'chunk-echarts',
priority: 20,
test: /[\\/]node_modules[\\/]_?echarts(.*)/,
chunks: 'all'
}
// moment: {
// priority: 20,
// test: /[\\/]node_modules[\\/]_?moment(.*)/,
// reuseExistingChunk: true
// }
}
}
}
},
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'))
//生产环境,开启js\css压缩
if (process.env.NODE_ENV === 'production') {
config.plugin('compressionPlugin').use(
new CompressionPlugin({
test: /\.(js|css|less)$/, // 匹配文件名
threshold: 10240, // 对超过10k的数据压缩
deleteOriginalAssets: false // 不删除源文件
})
)
}
// 配置 webpack 识别 markdown 为普通的文件
config.module
.rule('markdown')
.test(/\.md$/)
.use()
.loader('file-loader')
.end()
// 编译vxe-table包里的es6代码,解决IE11兼容问题
config.module
.rule('vxe')
.test(/\.js$/)
.include.add(resolve('node_modules/vxe-table'))
.add(resolve('node_modules/vxe-table-plugin-antd'))
.end()
.use()
.loader('babel-loader')
.end()
},
css: {
loaderOptions: {
less: {
modifyVars: {
/* less 变量覆盖,用于自定义 ant design 主题 */
'primary-color': '#1890FF',
'link-color': '#1890FF',
'border-radius-base': '4px'
},
javascriptEnabled: true
}
}
},
devServer: {
port: 3000,
// hot: true,
// disableHostCheck: true,
// overlay: {
// warnings: false,
// errors: true,
// },
// headers: {
// 'Access-Control-Allow-Origin': '*',
// },
proxy: {
/* '/api': {
target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro', //mock API接口系统
ws: false,
changeOrigin: true,
pathRewrite: {
'/jeecg-boot': '' //默认所有请求都加了jeecg-boot前缀,需要去掉
}
},*/
'/jeecg-boot': {
target: 'http://localhost:8080', //请求本地 需要jeecg-boot后台项目
ws: false,
changeOrigin: true
}
}
},
lintOnSave: undefined
}
? 图片如何添加水印步骤:1、选择图片,2、创建canvas对象,ctx.drawImage把图片放入到canvas中,3、设置水印的位置、大小、颜色,4、执行ctx.draw()方 法在回调函数中将执行canvas.canvasToTempFilePath()方法,canvas转换成图片,5、将生成的图片上传到服务器并回显图片
问题:选择多个图片后只上传了一张图片? 原因:遍历多张图片的时间快于canvas.draw回调方法执行时间,canvas.draw回调函数只执行了一次,导致只能上传一张图片
解决:通过使用promise方式解决,在循环中使用promise,promise回调函数执行canvas.draw方法,只有执行完第一次的promise回调函数改变了状态,才会执行第二次的promise,因此canvas.draw方法也会执行多次,就可以上传多个图片了。
for (let item of that.data.imgList) {
// 循环遍历promise
const data = await this.getCanvasImg(item)
this.uploadFile(data);
}
getCanvasImg(item) {
const that = this
return new Promise((resolve, reject) => {
console.log(245);
let ctx = that.data.ctx
console.log("获取图片详情", ctx)
//将图片src放到cancas内,宽高为图片大小
ctx.drawImage(item, 0, 0, 375, 375)
//将声明的时间放入canvas
ctx.setFontSize(18) //注意:设置文字大小必须放在填充文字之前,否则不生效
// 添加水印
// 日期时间
const watermar = that.data.watermarks
watermar[0].text = getTime()
for (let index = 0; index < watermar.length; index++) {
const element = watermar[index];
ctx.setFillStyle(element.color)
ctx.fillText(element.text, element.x, element.y)
ctx.strokeText(element.text, element.x, element.y)
}
ctx.draw(true, function () {
wx.canvasToTempFilePath({
canvasId: 'firstCanvas',
success: (res) => {
resolve([res.tempFilePath])
},
fail: (e) => {
console.log(e)
}
}, that)
})
})
},
uploadFile(arrImg) {
console.log('arrImg', arrImg);
wx.showLoading({
title: '正在上传',
})
var that = this;
var t = 0;
for (var i = 0; i < arrImg.length; i++) {
wx.uploadFile({
url: api.upload.img,
filePath: arrImg[i],
name: 'file',
dataType: "json",
success: function (res) {
console.log(272, res);
var redata = JSON.parse(res.data);
if (t < arrImg.length) {
if (redata.code == 200) {
setTimeout(function () {
that.setTopicResource(redata.data, 1);
}, 500)
} else {
// app.showError('请上传小于5M的图片')
}
wx.hideLoading();
}
t++;
},
})
}
},