详解Webpack4多页应用打包方案

前言

学习了 webpack 之后,将自己的博客的前端进行重构,由于自己的博客是多页应用,所以研究了下多页应用的打包方案。在这里把最后配置的成果分享下,不足之处,请指正。(文字不多,全是代码,不是配置教程,所以没有特别详细的写,只是一个参考)

项目地址: https://github.com/Ray-daydayup/MPA-webpack

文件目录结构

项目目录结构

首先先看下我的项目的目录结构

myblog-webpack
 ├── dist           // 打包输出文件夹
 ├── src           // 源代码
 │  ├── api         // 请求文件夹,存放封装的请求方法
 │  ├── assets        // 静态资源文件夹
 │  ├── lib         // 一些库
 │  ├── pages        // 页面
 │  │  ├── about      // 页面名称
 │  │  │  ├── index.html  // html模板
 │  │  │  └── index.js   // 入口js
 │  │  ├── category
 │  │  │  ├── index.html
 │  │  │  └── index.js
 │  │  ├── detail
 │  │  │  ├── index.html
 │  │  │  └── index.js
 │  │  ├── index
 │  │  │  ├── index.html
 │  │  │  └── index.js
 │  │  └── tag
 │  │    ├── index.html
 │  │    └── index.js
 │  ├── styles       // 样式文件
 │  └── utils        // 工具函数
 ├── package.json
 ├── README.md
 ├── package-lock.json
 ├── webpack.base.js    // 公共配置
 ├── webpack.dev.js     // 开发环境配置
 └── webpack.prod.js    // 生产环境配置

打包输出文件目录结构

最终打包输出的目录如下

dist
 ├── assets
 ├── css
 │  ├── commons672a1e57.css
 │  └── index6085d612.css
 ├── js
 │  ├── aboutfc723f0e.js
 │  ├── categorye4be3bd6.js
 │  ├── commons78f1dd3f.js
 │  ├── detail0df434c5.js
 │  ├── indexe1e985d9.js
 │  ├── markdown-it
 │  │  ├── highlight.vendors.js
 │  │  ├── markdown-it-integrated.js
 │  │  ├── markdown-it-integrated.min.js
 │  │  ├── markdown-it-integrated.min.js.LICENSE.txt
 │  │  └── markdown-it.vendors.js
 │  └── tagf1c1035c.js
 ├── about.html
 ├── category.html
 ├── detail.html
 ├── favicon.ico
 ├── index.html
 └── tag.html

webpack 配置文件

注意:文中各部分所需的包名,并没有书写,请在附录中查找!!!相关配置的意义可以查找官方文档

公共配置

动态获取 entry 和设置 html-webpack-plugin

多页应用的打包思路是 每个页面对应一个 entry ,一个 html-webpack-plugin ,但每次新增或删除页面需要改 webpack 配置,所以需要根据文件目录动态获取入口,来设置 html-webpack-plugin 。

利用一个库 glob 来实现对文件目录的读取 具体代码如下,相关配置的意义可以查找官方文档

const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const setMPA = () => {
 const entry = {}
 const htmlWebpackPlugins = []
 const entryFiles = glob.sync(path.join(__dirname, './src/pages/*/index.js')) // 匹配各页面的对应入口文件
 entryFiles.forEach((item) => {
  const pageName = item.match(/pages\/(.*)\/index.js/)[1] // 获取文件夹名,即页面名称
  entry[pageName] = item                  // 设置入口文件路径
  // 设置html-webpack-plugin数组
  htmlWebpackPlugins.push(
   new HtmlWebpackPlugin({
    template: path.join(__dirname, `./src/pages/${pageName}/index.html`),//模板地址
    filename: `${pageName}.html`, //输出文件名
    chunks: [pageName], // 插入的js chunk名称,和output有关
    inject: true,
    favicon: path.join(__dirname, './src/assets/favicon.ico'), // 图标
    minify: { //压缩代码
     html5: true,
     collapseWhitespace: true,
     preserveLineBreaks: false,
     minifyCSS: true,
     minifyJS: true,
     removeComments: false
    }
   })
  )
 })
 return {
  entry,
  htmlWebpackPlugins
 }
}

const { entry, htmlWebpackPlugins } = setMPA()

使用 ES6 和 async、await ,以及 eslint

使用 ES6 和 async、await 以及 eslint ,需要借助 babel-loader 和 eslint-loader ,其具体配置很简单

babel 相关的库: @babel/core 、 @babel/preset-env 、 @babel/plugin-transform-regenerator 、 @babel/plugin-transform-runtime 、 eslint 相关的库: babel-eslint 、 eslint

module.rules 的配置

{
  test: /\.js$/,
  use: ['babel-loader', 'eslint-loader']
}

.babelrc 文件的配置

{
 "presets": [
  "@babel/preset-env"
 ],
 "plugins": [ //设置支持async和await
  "@babel/plugin-transform-runtime",
  "@babel/plugin-transform-regenerator"
 ]
}

.eslintrc.js 的配置

module.exports = {
 parser: 'babel-eslint',
 extends: ['alloy'], // eslint标准请自行选择下载
 env: {
  browser: true,
  node: true
 },
 rules: {
  'no-new': 'off',
  'no-proto': 'off'
  // 'no-console': 'error'
 }
}

加载图片

利用 url-loader ,具体 module.rules 配置如下

{
  test: /\.(png|svg|jpg|gif)$/,
  use: [
   {
    loader: 'url-loader',
    options: {
     esModule: false,
     name: '[name][hash:8].[ext]', //文件指纹
     limit: 10240,         // 转base64
     outputPath: './assets/images/' // 图片文件输出目录和publicPath有关
    }
   }
  ]
 }

清理打包目录和复制文件到打包目录

自动清理打包目录利用 clean-webpack-plugin 插件,复制文件利用 copy-webpack-plugin

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

const basePlugins = [
 ...htmlWebpackPlugins, //之前配置的htmlWebpackPlugin数组
 new CleanWebpackPlugin(), // 自动清理构建目录
 new CopyWebpackPlugin({
  patterns: [
   {
    from: path.join(__dirname, 'src/lib/markdown-it'), // 源
    to: path.join(__dirname, 'dist/js/markdown-it') // 目标位置
   }
  ]
 })
]

.browserslistrc 配置

# Browsers that we support

last 2 version
> 1%
iOS 7

开发环境配置

热更新以及 devServer

具体配置如下:

plugins: [...basePlugins, new webpack.HotModuleReplacementPlugin()], //热更新插件
devServer: {
  contentBase: 'dist', // 开启服务的目录
  hot: true, //热更新开启
  proxy: {
   '/api': {
    target: 'http://raydaydayup.cn:3000', //代理
    pathRewrite: { '^/api': '' }
   }
  }
}

CSS 相关配置

module.rules 的配置如下

{
  test: /\.less$/,
  use: ['style-loader', 'css-loader', 'less-loader']
},
{
  test: /\.css$/,
  use: ['style-loader', 'css-loader']
}

出口

output: {
  filename: '[name].js',
  path: path.join(__dirname, 'dist')
}

生产环境配置

出口

output: {
  filename: 'js/[name][chunkhash:8].js', // 统一输出到js文件夹
  path: path.join(__dirname, 'dist'),
  publicPath: '/' // 服务路径
}

js 代码压缩

利用 terser-webpack-plugin 插件,配置 optimization

const TerserPlugin = require('terser-webpack-plugin')

optimization: {
  minimize: true,
  minimizer: [
   new TerserPlugin({
    include: [/\.js$/]
   })
  ]
}

CSS 相关配置

CSS 代码压缩,利用 optimize-css-assets-webpack-plugin 和 cssnano

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')

plugins: [
 new OptimizeCSSAssetsPlugin({
   assetNameRegExp: /\.css$/g,
   cssProcessor: require('cssnano')
  })
]

CSS 分离单独文件,利用 mini-css-extract-plugin

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module: {
 rules: [
   ...baseModuleRules,
   {
    test: /\.less$/,
    use: [
     {
      loader: MiniCssExtractPlugin.loader,
      options: {
       esModule: true
      }
     },
     'css-loader',
     'less-loader'
    ]
   },
   {
    test: /\.css$/,
    use: [
     {
      loader: MiniCssExtractPlugin.loader,
      options: {
       esModule: true
      }
     },
     'css-loader'
    ]
   }
  ]
},
plugins: [
  ...basePlugins,
  new MiniCssExtractPlugin({
   filename: 'css/[name][contenthash:8].css' // 输出文件名和地址
  }),
 ],

PostCSS 插件 autoprefixer 自动补齐 CSS3 前缀

module: {
  rules: [
   ...baseModuleRules,
   {
    test: /\.less$/,
    use: [
     {
      loader: MiniCssExtractPlugin.loader,
      options: {
       esModule: true
      }
     },
     'css-loader',
     {
      loader: 'postcss-loader',
      options: {
       plugins: () => [require('autoprefixer')]
      }
     },
     'less-loader'
    ]
   },
  ]
 },

分离公共文件(CSS和JS)

配置 optimization.splitChunks

optimization: {
  splitChunks: {
   cacheGroups: {
    commons: {
     name: 'commons',
     chunks: 'all',
     minChunks: 2 // 最少引用两次
    }
   }
  }
 }

使用相关注意

html-webpack-plugin 模板使用以及 html-loader

导入 html 片段,在相应位置写下面的代码就像,需要注意的是, html-loader 加载的 html 片段内部 <%%> 语法会失效

<%= require("html-loader!@/components/recent.html") %>

html 中图片的加载。在 html 中相关的 img 标签的图片, html-loader 加载时会自动调用 url-loader ,但是存在问题,加载出来的路径没有 "" 。为了避免这个问题,我就没有再 html-loader 加载的 html 片段中使用图片,而是直接再 html 模

板中直接用 require

<img src="<%= require('@/assets/logo362x82.png') %>" alt="" />

附录

配置文件完整版

webpack.base.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin')

const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

const setMPA = () => {
 const entry = {}
 const htmlWebpackPlugins = []
 const entryFiles = glob.sync(path.join(__dirname, './src/pages/*/index.js'))
 entryFiles.forEach((item) => {
  const pageName = item.match(/pages\/(.*)\/index.js/)[1]
  entry[pageName] = item
  htmlWebpackPlugins.push(
   new HtmlWebpackPlugin({
    template: path.join(__dirname, `./src/pages/${pageName}/index.html`),
    filename: `${pageName}.html`,
    chunks: [pageName],
    inject: true,
    favicon: path.join(__dirname, './src/assets/favicon.ico'),
    minify: {
     html5: true,
     collapseWhitespace: true,
     preserveLineBreaks: false,
     minifyCSS: true,
     minifyJS: true,
     removeComments: false
    }
   })
  )
 })
 return {
  entry,
  htmlWebpackPlugins
 }
}

const { entry, htmlWebpackPlugins } = setMPA()

const baseModuleRules = [
 {
  test: /\.js$/,
  use: ['babel-loader', 'eslint-loader']
 },
 {
  test: /\.(png|svg|jpg|gif)$/,
  use: [
   {
    loader: 'url-loader',
    options: {
     esModule: false,
     name: '[name][hash:8].[ext]',
     limit: 10240,
     outputPath: './assets/images/'
    }
   }
  ]
 }
]

const basePlugins = [
 ...htmlWebpackPlugins,
 new CleanWebpackPlugin(),
 new CopyWebpackPlugin({
  patterns: [
   {
    from: path.join(__dirname, 'src/lib/markdown-it'),
    to: path.join(__dirname, 'dist/js/markdown-it')
   }
  ]
 })
]
module.exports = {
 entry,
 baseModuleRules,
 basePlugins
}

webpack.dev.js

const webpack = require('webpack')
const path = require('path')
const { entry, baseModuleRules, basePlugins } = require('./webpack.base.js')

module.exports = {
 mode: 'development',
 entry,
 output: {
  filename: '[name].js',
  path: path.join(__dirname, 'dist')
 },
 module: {
  rules: [
   ...baseModuleRules,
   {
    test: /\.less$/,
    use: ['style-loader', 'css-loader', 'less-loader']
   },
   {
    test: /\.css$/,
    use: ['style-loader', 'css-loader']
   }
  ]
 },
 resolve: {
  // 设置别名
  alias: {
   '@': path.join(__dirname, 'src') // 这样配置后 @ 可以指向 src 目录
  }
 },
 plugins: [...basePlugins, new webpack.HotModuleReplacementPlugin()],
 devServer: {
  contentBase: 'dist',
  hot: true,
  proxy: {
   '/api': {
    target: 'http://raydaydayup.cn:3000',
    pathRewrite: { '^/api': '' }
   }
  }
 }
}

webpack.prod.js

const { entry, baseModuleRules, basePlugins } = require('./webpack.base.js')
const path = require('path')
const TerserPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
 mode: 'production',
 entry,
 output: {
  filename: 'js/[name][chunkhash:8].js',
  path: path.join(__dirname, 'dist'),
  publicPath: '/'
 },
 resolve: {
  // 设置别名
  alias: {
   '@': path.resolve('src') // 这样配置后 @ 可以指向 src 目录
  }
 },
 module: {
  rules: [
   ...baseModuleRules,
   {
    test: /\.less$/,
    use: [
     {
      loader: MiniCssExtractPlugin.loader,
      options: {
       esModule: true
      }
     },
     'css-loader',
     {
      loader: 'postcss-loader',
      options: {
       plugins: () => [require('autoprefixer')]
      }
     },
     'less-loader'
    ]
   },
   {
    test: /\.css$/,
    use: [
     {
      loader: MiniCssExtractPlugin.loader,
      options: {
       esModule: true
      }
     },
     'css-loader'
    ]
   }
  ]
 },
 plugins: [
  ...basePlugins,
  new MiniCssExtractPlugin({
   filename: 'css/[name][contenthash:8].css'
  }),
  new OptimizeCSSAssetsPlugin({
   assetNameRegExp: /\.css$/g,
   cssProcessor: require('cssnano')
  })
 ],
 optimization: {
  minimize: true,
  minimizer: [
   new TerserPlugin({
    include: [/\.js$/]
   })
  ],
  splitChunks: {
   cacheGroups: {
    commons: {
     name: 'commons',
     chunks: 'all',
     minChunks: 2
    }
   }
  }
 }
}

package.json文件

{
 "name": "myblog-webpack",
 "version": "1.0.0",
 "description": "",
 "main": ".eslintrc.js",
 "scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "build": "webpack --config webpack.prod.js",
  "dev": "webpack-dev-server --config webpack.dev.js --open"
 },
 "keywords": [],
 "author": "",
 "license": "ISC",
 "devDependencies": {
  "@babel/core": "^7.10.2",
  "@babel/plugin-transform-regenerator": "^7.10.3",
  "@babel/plugin-transform-runtime": "^7.10.3",
  "@babel/preset-env": "^7.10.2",
  "autoprefixer": "^9.8.4",
  "babel-eslint": "^10.1.0",
  "babel-loader": "^8.1.0",
  "clean-webpack-plugin": "^3.0.0",
  "copy-webpack-plugin": "^6.0.3",
  "css-loader": "^3.6.0",
  "cssnano": "^4.1.10",
  "eslint": "^7.2.0",
  "eslint-config-alloy": "^3.7.2",
  "eslint-loader": "^4.0.2",
  "file-loader": "^6.0.0",
  "glob": "^7.1.6",
  "html-loader": "^1.1.0",
  "html-webpack-plugin": "^4.3.0",
  "less-loader": "^6.1.2",
  "mini-css-extract-plugin": "^0.9.0",
  "optimize-css-assets-webpack-plugin": "^5.0.3",
  "postcss-loader": "^3.0.0",
  "style-loader": "^1.2.1",
  "terser-webpack-plugin": "^3.0.5",
  "url-loader": "^4.1.0",
  "webpack": "^4.43.0",
  "webpack-cli": "^3.3.11",
  "webpack-dev-server": "^3.11.0"
 },
 "dependencies": {
  "axios": "^0.19.2"
 }
}

到此这篇关于详解Webpack4多页应用打包方案的文章就介绍到这了,更多相关Webpack4多应用打包内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue项目中运用webpack动态配置打包多种环境域名的方法

    在如今前后端分离,各种框架盛行的前端界,对项目的打包要求也越来越复杂,本人分享一个vue项目里,根据命令行输入不同的命令,打包出不同环境域名的方法.(欢迎纠错,谢谢.) 1. 安装插件 cross-env,npm install cross-env --save -dev,用于配置命令行输入命令. 2. 修改package.json里的script命令: 配置了test(测试),ready(预发布),prod(正式)三种环境,npm run build 默认设置成 npm run build:p

  • webpack4打包vue前端多页面项目

    之前一直用的脚手架,这次自己搭建webpack前端项目,花费了不少心思,于是做个总结. 1.用法 项目结构如下: project |- bulid <!-- 这个目录是自动生成的--> |- public |- css |- js |- page1.html <!-- 插件生成的html文件--> |- page2.html <!-- 插件生成的html文件--> ... |- public/ <!-- 存放字体.图片.网页模板等静态资源--> |- src

  • webpack打包多页面的方法

    前言 一开始接触webpack是因为使用Vue的关系,因为Vue的脚手架就是使用webpack构建的.刚开始的时候觉得webpack就是为了打包单页面而生的,后来想想,这么好的打包方案,只在单页面上使用是否太浪费资源了呢?如果能在传统多页面上使用webpack,开始效率是否会事半功倍呢?好在众多优秀的前端开发者已经写了许多demo和文章供人学习.我也写了一个小项目,希望对大家学习webpack有帮助. 好吧其实上面说的都是废话,接下来附上项目地址和干货,配合食用更佳. webpack-multi

  • webpack 3.X学习之多页面打包的方法

    简介 我们开发不可能只写一个页面,每次都要写很多页面,这时为了开发效率,我们使用前端自动化工具webpack,那么webpack是如何打包页面的呢?又是如何打包多页面的呢? 单页面打包 我们知道要打包单页面的方法,很简单,配置入口,和html插件, const HtmlWebpackPlugin = require('html-webpack-plugin'); const config = { entry:{ index:'./src/index.js' }, output:{ path: p

  • Vue.js中用webpack合并打包多个组件并实现按需加载

    前言 随着移动设备的升级.网络速度的提高,用户对于web应用的要求越来越高,web应用要提供的功能越来越.功能的增加导致的最直观的后果就是资源文件越来越大.为了维护越来越庞大的客户端代码,提出了模块化的概念来组织代码.webpack作为一种模块化打包工具,随着react的流行也越来越流行. 使用 Vue 开发项目时,如果要使用其单文件组件特性,必然要使用 webpack 或者 browserify 进行打包,对于大型应用,为了提升加载速度,可以使用 webpack 的 code split 功能

  • 详解Webpack多环境代码打包的方法

    在实际开发中常遇到,代码在 在package.json文件的scripts中,会提供开发环境与生产环境两个命令.但是实际使用中会遇见 测试版与正式版代码相继发布的情况,这样反复更改服务器地址,偶尔忘记更改url会给工作带来很多不必要的麻烦(当然也会对你的工作能力产生质疑).这样就需要在生产环境中配置测试版本打包命令与正式版本打包命令. 1.Package.json 文件中 增加命令行命令,并指定路径. "scripts": { "dev": "node b

  • 详解Webpack4多页应用打包方案

    前言 学习了 webpack 之后,将自己的博客的前端进行重构,由于自己的博客是多页应用,所以研究了下多页应用的打包方案.在这里把最后配置的成果分享下,不足之处,请指正.(文字不多,全是代码,不是配置教程,所以没有特别详细的写,只是一个参考) 项目地址: https://github.com/Ray-daydayup/MPA-webpack 文件目录结构 项目目录结构 首先先看下我的项目的目录结构 myblog-webpack ├── dist // 打包输出文件夹 ├── src // 源代码

  • 详解webpack模块化管理和打包工具

    本篇文章主要介绍了详解webpack模块化管理和打包工具,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 Webpack简介 webpack是当下最热门的前端资源模块化管理和打包工具. 它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源.还可以将按需加载的模块进行代码分隔,等到实际 需要的时候再异步加载.通过 loader  的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块. AMD 模块. ES6 模块.CSS.图片. JSON.

  • 详解Vue适时清理keepalive缓存方案

    目录 需求 思考 尝试 1. 手动操作 keep-alive 组件的 cache 数组 2. exclude 大法好 Demo 需求 单页面应用中,用户进入表单填写页面,需要初始化表单内容,填写过程中可能涉及到地图选点或者列表选择等操作,需要到新的页面选择并回调显示. 此时我们需要缓存表单填写页面实例,当退出表单填写或提交完表单内容之后,需要销毁当前表单实例,下次进入重新进行初始化 思考 说到 Vue 缓存,我们肯定首先选择官方提供的缓存方案 keep-alive 内置组件来实现. keep-a

  • 详解基于Mybatis-plus多租户实现方案

    一.引言 小编先解释一下什么叫多租户,什么场景下使用多租户. 多租户是一种软件架构技术,在多用户的环境下,共有同一套系统,并且要注意数据之间的隔离性. 举个实际例子:小编曾经开发过一套支付宝程序,这套程序应用在不同的小程序上,当使用者访问不同,并且进入相对应的小程序页面,小程序则会把用户相关数据传输到小编这里.在传输的时候需要带上小程序标识(租户ID),以便小编将数据进行隔离. 当不同的租户使用同一套程序,这里就需要考虑一个数据隔离的情况. 数据隔离有三种方案: 1.独立数据库:简单来说就是一个

  • 详解使用mocha对webpack打包的项目进行"冒烟测试"的大致流程

    第一步: 打包开始之前删除'./dist'目录 rimraf('./dist', () => { constprodConfig = require('../../lib/webpack.prod') webpack(prodConfig, (err, stats) \=> { if (err) { console.log(err) process.exit(2) } console.log(stats.toString({ color:true, modules:false, childre

  • 详解Js模块化的作用原理和方案

    一.模块化概念 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起:块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信. 二.模块化作用 为什么要用模块化的JavaScript? 因为在实际的开发过程中,经常会遇到变量.函数.对象等名字的冲突,这样就容易造成冲突,还会造成全局变量被污染: 同时,程序复杂时需要写很多代码,而且还要引入很多类库,这样稍微不注意就容易造成文件依赖混乱: 为了解决上面的的问题,我们才开始使用模块化的js,所以说模块

  • 详解Android内存泄露及优化方案一

    目录 一.常见的内存泄露应用场景? 1.单例的不恰当使用 2.静态变量导致内存泄露 3.非静态内部类导致内存泄露 4.未取消注册或回调导致内存泄露 5.定时器Timer 和 TimerTask 导致内存泄露 6.集合中的对象未清理造成内存泄露 7.资源未关闭或释放导致内存泄露 8.动画造成内存泄露 9.WebView 造成内存泄露 总结 一.常见的内存泄露应用场景? 1.单例的不恰当使用 单例是我们开发中最常见和使用最频繁的设计模式之一,所以如果使用不当就会导致内存泄露.因为单例的静态特性使得它

  • 详解iOS 实现一对多代理方案

    目录 实现方案一 实现方案二 实现方案一 利用可变数组. 签协议方需要add到代理的数组中, 然后协议遍历数组中的对象,进行分发.缺点是需要数组对其内部元素是强引用, 需要在合适的地方对其进行释放,否则会有内存泄漏 代理协议的对象.h写法 #import <UIKit/UIKit.h> NS_ASSUME_NONNULL_BEGIN @protocol TestSubViewDelegate <NSObject> - (void)testSendSomeMessageToOther

  • 详解Android内存泄露及优化方案

    目录 一.常见的内存泄露应用场景? 1.单例的不恰当使用 2.静态变量导致内存泄露 3.非静态内部类导致内存泄露 4.未取消注册或回调导致内存泄露 5.定时器Timer 和 TimerTask 导致内存泄露 6.集合中的对象未清理造成内存泄露 7.资源未关闭或释放导致内存泄露 8.动画造成内存泄露 9.WebView 造成内存泄露 总结 一.常见的内存泄露应用场景? 1.单例的不恰当使用 单例是我们开发中最常见和使用最频繁的设计模式之一,所以如果使用不当就会导致内存泄露.因为单例的静态特性使得它

  • 详解vue 单页应用(spa)前端路由实现原理

    写在前面:通常 SPA 中前端路由有2种实现方式: window.history location.hash 下面就来介绍下这两种方式具体怎么实现的 一.history 1.history基本介绍 window.history 对象包含浏览器的历史,window.history 对象在编写时可不使用 window 这个前缀.history是实现SPA前端路由是一种主流方法,它有几个原始方法: history.back() - 与在浏览器点击后退按钮相同 history.forward() - 与

随机推荐