vue-cli webpack配置文件分析


Posted in Javascript onMay 20, 2019

相信vue使用者对vue-cli都不会陌生,甚至可以说,很熟悉了,但对其webpack的配置可能知之甚少吧。

过完年回来后,我接手了公司的新项目。新项目是一个spa。很自然,我就想到了vue-cli脚手架了,当时研究一下它的webpack配置。于是,就有了其他的内容。

今天这篇文章,是在原来的基础上,增加了一些新版本的内容,但实质上变化不大。

说明

此仓库为vue-cli webpack的配置分析,其实只是在源码中加上注释而已。大家查看详细分析,可以从后面提到的入口文件开始查看。

分析不包括check-versions.js文件,因为check-versions.js是检测npm和node版本,不涉及webpack,所以就没有对check-versions.js进行分析。同时,也不包括测试部分的代码,该分析只是针对开发和生产环境的webpack配置进行分析。

vue-cli 版本

2.8.1

入口

从package.json可以看到开发和生产环境的入口。

"scripts": {
  "dev": "node build/dev-server.js",
  "build": "node build/build.js"
 }

开发环境

开发环境的入口文件是 build/dev-server.js。

dev-server.js

该文件中,使用express作为后端框架,结合一些关于webpack的中间件,搭建了一个开发环境。

// 配置文件
var config = require('../config')
// 如果 Node 的环境无法判断当前是 dev / product 环境
// 使用 config.dev.env.NODE_ENV 作为当前的环境
if (!process.env.NODE_ENV) {
 process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}

// 可以强制打开浏览器并跳转到指定 url 的插件
// https://github.com/sindresorhus/opn
var opn = require('opn')
// node自带的文件路径工具
var path = require('path')
// express框架
var express = require('express')
var webpack = require('webpack')
// 测试环境,使用的配置与生产环境的配置一样
// 非测试环境,即为开发环境,因为此文件只有测试环境和开发环境使用
var proxyMiddleware = require('http-proxy-middleware')
var webpackConfig = process.env.NODE_ENV === 'testing'
// 生产环境配置文件
 ? require('./webpack.prod.conf')
 // 开发环境配置文件
 : require('./webpack.dev.conf')

// 端口号为命令行输入的PORT参数或者配置文件中的默认值
var port = process.env.PORT || config.dev.port
// 配置文件中 是否自动打开浏览器
var autoOpenBrowser = !!config.dev.autoOpenBrowser
// 配置文件中 http代理配置
// https://github.com/chimurai/http-proxy-middleware
var proxyTable = config.dev.proxyTable

// 启动 express 服务
var app = express()
// 启动 webpack 编译
var compiler = webpack(webpackConfig)

// 可以将编译后的文件暂存到内存中的插件
// https://github.com/webpack/webpack-dev-middleware
var devMiddleware = require('webpack-dev-middleware')(compiler, {
 // 公共路径,与webpack的publicPath一样
 publicPath: webpackConfig.output.publicPath,
 // 不打印
 quiet: true
})

// Hot-reload 热重载插件
// https://github.com/glenjamin/webpack-hot-middleware
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
 log: () => {}
})
// 当tml-webpack-plugin template更改之后,强制刷新浏览器
compiler.plugin('compilation', function (compilation) {
 compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
  hotMiddleware.publish({ action: 'reload' })
  cb()
 })
})

// 将 proxyTable 中的请求配置挂在到启动的 express 服务上
Object.keys(proxyTable).forEach(function (context) {
 var options = proxyTable[context]
 // 如果options的数据类型为string,则表示只设置了url,
 // 所以需要将url设置为对象中的 target的值
 if (typeof options === 'string') {
  options = { target: options }
 }
 app.use(proxyMiddleware(options.filter || context, options))
})

// 使用 connect-history-api-fallback 匹配资源
// 如果不匹配就可以重定向到指定地址
// https://github.com/bripkens/connect-history-api-fallback
app.use(require('connect-history-api-fallback')())

// 将暂存到内存中的 webpack 编译后的文件挂在到 express 服务上
app.use(devMiddleware)

// 将 Hot-reload 挂在到 express 服务上
app.use(hotMiddleware)

// 拼接 static 文件夹的静态资源路径
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
// 静态文件服务
app.use(staticPath, express.static('./static'))

var uri = 'http://localhost:' + port

// 编译成功后打印网址信息
devMiddleware.waitUntilValid(function () {
 console.log('> Listening at ' + uri + '\n')
})

module.exports = app.listen(port, function (err) {
 if (err) {
  console.log(err)
  return
 }

 // 如果配置了自动打开浏览器,且不是测试环境,则自动打开浏览器并跳到我们的开发地址
 if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
  opn(uri)
 }
})

webpack.dev.conf.js

dev-server.js中使用了webpack.dev.conf.js文件,该文件是开发环境中webpack的配置入口。

// 工具函数集合
var utils = require('./utils')
var webpack = require('webpack')
 // 配置文件
var config = require('../config')
 // webpack 配置合并插件
var merge = require('webpack-merge')
 // webpac基本配置
var baseWebpackConfig = require('./webpack.base.conf')
 // 自动生成 html 并且注入到 .html 文件中的插件
 // https://github.com/ampedandwired/html-webpack-plugin
var HtmlWebpackPlugin = require('html-webpack-plugin')
 // webpack错误信息提示插件
 // https://github.com/geowarin/friendly-errors-webpack-plugin
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

// 将 Hol-reload 热重载的客户端代码添加到 webpack.base.conf 的 对应 entry 中,一起打包
Object.keys(baseWebpackConfig.entry).forEach(function(name) {
 baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

module.exports = merge(baseWebpackConfig, {
 module: {
  // styleLoaders
  rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
 },
 // 最新的配置为 cheap-module-eval-source-map,虽然 cheap-module-eval-source-map更快,但它的定位不准确
 // 所以,换成 eval-source-map
 devtool: '#eval-source-map',
 plugins: [
  // definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
  // 此处,插入适当的环境
  // https://webpack.js.org/plugins/define-plugin/
  new webpack.DefinePlugin({
   'process.env': config.dev.env
  }),
  // HotModule 插件在页面进行变更的时候只会重绘对应的页面模块,不会重绘整个 html 文件
  // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoEmitOnErrorsPlugin(),
  // 将 index.html 作为入口,注入 html 代码后生成 index.html文件
  // https://github.com/ampedandwired/html-webpack-plugin
  new HtmlWebpackPlugin({
   filename: 'index.html',
   template: 'index.html',
   inject: true
  }),
  // webpack错误信息提示插件
  new FriendlyErrorsPlugin()
 ]
})

webpack.base.conf.js

在webpack.dev.conf.js中出现webpack.base.conf.js,这个文件是开发环境和生产环境,甚至测试环境,这些环境的公共webpack配置。可以说,这个文件相当重要。

// node自带的文件路径工具
var path = require('path')
// 工具函数集合
var utils = require('./utils')
 // 配置文件
var config = require('../config')
 // 工具函数集合
var vueLoaderConfig = require('./vue-loader.conf')

/**
 * 获得绝对路径
 * @method resolve
 * @param {String} dir 相对于本文件的路径
 * @return {String}   绝对路径
 */
function resolve(dir) {
 return path.join(__dirname, '..', dir)
}

module.exports = {
 entry: {
  app: './src/main.js'
 },
 output: {
  // 编译输出的静态资源根路径
  path: config.build.assetsRoot,
  // 编译输出的文件名
  filename: '[name].js',
  // 正式发布环境下编译输出的上线路径的根路径
  publicPath: process.env.NODE_ENV === 'production' ?
   config.build.assetsPublicPath : config.dev.assetsPublicPath
 },
 resolve: {
  // 自动补全的扩展名
  extensions: ['.js', '.vue', '.json'],
  // 路径别名
  alias: {
   // 例如 import Vue from 'vue',会自动到 'vue/dist/vue.common.js'中寻找
   'vue$': 'vue/dist/vue.esm.js',
   '@': resolve('src'),
  }
 },
 module: {
  rules: [{
    // 审查 js 和 vue 文件
    // https://github.com/MoOx/eslint-loader
    test: /\.(js|vue)$/,
    loader: 'eslint-loader',
    // 表示预先处理
    enforce: "pre",
    include: [resolve('src'), resolve('test')],
    options: {
     formatter: require('eslint-friendly-formatter')
    }
   },
   {
    // 处理 vue文件
    // https://github.com/vuejs/vue-loader
    test: /\.vue$/,
    loader: 'vue-loader',
    options: vueLoaderConfig
   },
   {
    // 编译 js
    // https://github.com/babel/babel-loader
    test: /\.js$/,
    loader: 'babel-loader',
    include: [resolve('src'), resolve('test')]
   },
   {
    // 处理图片文件
    // https://github.com/webpack-contrib/url-loader
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: 'url-loader',
    query: {
     limit: 10000,
     name: utils.assetsPath('img/[name].[hash:7].[ext]')
    }
   },
   {
    // 处理字体文件
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    query: {
     limit: 10000,
     name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
    }
   }
  ]
 }
}

config/index.js

该文件在很多文件中都用到,是主要的配置文件,包含静态文件的路径、是否开启sourceMap等。其中,分为两个部分dev(开发环境的配置)和build(生产环境的配置)。

// 详情见文档:https://vuejs-templates.github.io/webpack/env.html
var path = require('path')

module.exports = {
 // production 生产环境
 build: {
  // 构建环境
  env: require('./prod.env'),
  // 构建输出的index.html文件
  index: path.resolve(__dirname, '../dist/index.html'),
  // 构建输出的静态资源路径
  assetsRoot: path.resolve(__dirname, '../dist'),
  // 构建输出的二级目录
  assetsSubDirectory: 'static',
  // 构建发布的根目录,可配置为资源服务器域名或 CDN 域名
  assetsPublicPath: '/',
  // 是否开启 cssSourceMap
  productionSourceMap: true,
  // Gzip off by default as many popular static hosts such as
  // Surge or Netlify already gzip all static assets for you.
  // Before setting to `true`, make sure to:
  // npm install --save-dev compression-webpack-plugin
  // 默认关闭 gzip,因为很多流行的静态资源主机,例如 Surge、Netlify,已经为所有静态资源开启gzip
  productionGzip: false,
  // 需要使用 gzip 压缩的文件扩展名
  productionGzipExtensions: ['js', 'css'],
  // Run the build command with an extra argument to
  // View the bundle analyzer report after build finishes:
  // `npm run build --report`
  // Set to `true` or `false` to always turn it on or off
  // 运行“build”命令行时,加上一个参数,可以在构建完成后参看包分析报告
  // true为开启,false为关闭
  bundleAnalyzerReport: process.env.npm_config_report
 },
 // dev 开发环境
 dev: {
  // 构建环境
  env: require('./dev.env'),
  // 端口号
  port: 3333,
  // 是否自动打开浏览器
  autoOpenBrowser: true,
  assetsSubDirectory: 'static',
  // 编译发布的根目录,可配置为资源服务器域名或 CDN 域名
  assetsPublicPath: '/',
  // proxyTable 代理的接口(可跨域)
  // 使用方法:https://vuejs-templates.github.io/webpack/proxy.html
  proxyTable: {},
  // CSS Sourcemaps off by default because relative paths are "buggy"
  // with this option, according to the CSS-Loader README
  // (https://github.com/webpack/css-loader#sourcemaps)
  // In our experience, they generally work as expected,
  // just be aware of this issue when enabling this option.
  // 默认情况下,关闭 CSS Sourcemaps,因为使用相对路径会报错。
  // CSS-Loader README:https://github.com/webpack/css-loader#sourcemaps
  cssSourceMap: false
 }
}

utils.js

utils.js也是一个被使用频率的文件,这个文件包含了三个工具函数:

  • 生成静态资源的路径
  • 生成 ExtractTextPlugin对象或loader字符串
  • 生成 style-loader的配置
// node自带的文件路径工具
var path = require('path')
// 配置文件
var config = require('../config')
// 提取css的插件
// https://github.com/webpack-contrib/extract-text-webpack-plugin
var ExtractTextPlugin = require('extract-text-webpack-plugin')

/**
 * 生成静态资源的路径
 * @method assertsPath
 * @param {String}  _path 相对于静态资源文件夹的文件路径
 * @return {String}     静态资源完整路径
 */
exports.assetsPath = function (_path) {
 var assetsSubDirectory = process.env.NODE_ENV === 'production'
  ? config.build.assetsSubDirectory
  : config.dev.assetsSubDirectory
  // path.posix.join与path.join一样,不过总是以 posix 兼容的方式交互
 return path.posix.join(assetsSubDirectory, _path)
}

/**
 * 生成处理css的loaders配置
 * @method cssLoaders
 * @param {Object}  options 生成配置
 *              option = {
 *               // 是否开启 sourceMap
 *               sourceMap: true,
 *               // 是否提取css
 *               extract: true
 *              }
 * @return {Object}      处理css的loaders配置对象
 */
exports.cssLoaders = function (options) {
 options = options || {}

 var cssLoader = {
  loader: 'css-loader',
  options: {
   minimize: process.env.NODE_ENV === 'production',
   sourceMap: options.sourceMap
  }
 }
 /**
  * 生成 ExtractTextPlugin对象或loader字符串
  * @method generateLoaders
  * @param {Array}    loaders loader名称数组
  * @return {String|Object}    ExtractTextPlugin对象或loader字符串
  */
 function generateLoaders (loader, loaderOptions) {
  var loaders = [cssLoader]
  if (loader) {
   loaders.push({
    // 例如,sass?indentedSyntax
    // 在?号前加上“-loader”
    loader: loader + '-loader',
    options: Object.assign({}, loaderOptions, {
     sourceMap: options.sourceMap
    })
   })
  }

  // extract为true时,提取css
  // 生产环境中,默认为true
  if (options.extract) {
   return ExtractTextPlugin.extract({
    use: loaders,
    fallback: 'vue-style-loader'
   })
  } else {
   return ['vue-style-loader'].concat(loaders)
  }
 }

 // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
 return {
  css: generateLoaders(),
  postcss: generateLoaders(),
  less: generateLoaders('less'),
  sass: generateLoaders('sass', { indentedSyntax: true }),
  scss: generateLoaders('sass'),
  stylus: generateLoaders('stylus'),
  styl: generateLoaders('stylus')
 }
}

/**
 * 生成 style-loader的配置
 * style-loader文档:https://github.com/webpack/style-loader
 * @method styleLoaders
 * @param {Object}   options 生成配置
 *               option = {
 *                // 是否开启 sourceMap
 *                sourceMap: true,
 *                // 是否提取css
 *                extract: true
 *               }
 * @return {Array}       style-loader的配置
 */
exports.styleLoaders = function (options) {
 var output = []
 var loaders = exports.cssLoaders(options)
 for (var extension in loaders) {
  var loader = loaders[extension]
  output.push({
   test: new RegExp('\\.' + extension + '$'),
   use: loader
  })
 }
 return output
}

生产环境

开发环境的入口文件是build/build.js 。

build.js

该文件,为构建打包文件,会将源码进行构建(编译、压缩等)后打包。

// 设置当前环境为生产环境
process.env.NODE_ENV = 'production'

// loading 插件
// https://github.com/sindresorhus/ora
var ora = require('ora')
// 可以在 node 中执行`rm -rf`的工具
// https://github.com/isaacs/rimraf
var rm = require('rimraf')
// node自带的文件路径工具
var path = require('path')
// 在终端输出带颜色的文字
// https://github.com/chalk/chalk
var chalk = require('chalk')
var webpack = require('webpack')
// 配置文件
var config = require('../config')
var webpackConfig = require('./webpack.prod.conf')

// 在终端显示loading效果,并输出提示
var spinner = ora('building for production...')
spinner.start()

// 删除这个文件夹 (递归删除)
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
 if (err) throw err
 // 构建
 webpack(webpackConfig, function (err, stats) {
  // 构建成功

  // 停止 loading动画
  spinner.stop()
  if (err) throw err
  process.stdout.write(stats.toString({
   colors: true,
   modules: false,
   children: false,
   chunks: false,
   chunkModules: false
  }) + '\n\n')

  // 打印提示
  console.log(chalk.cyan(' Build complete.\n'))
  console.log(chalk.yellow(
   ' Tip: built files are meant to be served over an HTTP server.\n' +
   ' Opening index.html over file:// won\'t work.\n'
  ))
 })
})

webpack.prod.conf

该文件,为生产环境中webpack的配置入口。同时,它也依赖于前面提到的webpack.base.conf.js、utils.js和config/index.js。

// node自带的文件路径工具
var path = require('path')
// 工具函数集合
var utils = require('./utils')
var webpack = require('webpack')
// 配置文件
var config = require('../config')
// webpack 配置合并插件
var merge = require('webpack-merge')
// webpack 基本配置
var baseWebpackConfig = require('./webpack.base.conf')
// webpack 复制文件和文件夹的插件
// https://github.com/kevlened/copy-webpack-plugin
var CopyWebpackPlugin = require('copy-webpack-plugin')
// 自动生成 html 并且注入到 .html 文件中的插件
// https://github.com/ampedandwired/html-webpack-plugin
var HtmlWebpackPlugin = require('html-webpack-plugin')
// 提取css的插件
// https://github.com/webpack-contrib/extract-text-webpack-plugin
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// webpack 优化压缩和优化 css 的插件
// https://github.com/NMFR/optimize-css-assets-webpack-plugin
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

// 如果当前环境为测试环境,则使用测试环境
// 否则,使用生产环境
var env = process.env.NODE_ENV === 'testing'
 ? require('../config/test.env')
 : config.build.env

var webpackConfig = merge(baseWebpackConfig, {
 module: {
  // styleLoaders
  rules: utils.styleLoaders({
   sourceMap: config.build.productionSourceMap,
   extract: true
  })
 },
 // 是否开启 sourceMap
 devtool: config.build.productionSourceMap ? '#source-map' : false,
 output: {
  // 编译输出的静态资源根路径
  path: config.build.assetsRoot,
  // 编译输出的文件名
  filename: utils.assetsPath('js/[name].[chunkhash].js'),
  // 没有指定输出名的文件输出的文件名
  chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
 },
 plugins: [
  // definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
  // 此处,插入适当的环境
  // http://vuejs.github.io/vue-loader/en/workflow/production.html
  new webpack.DefinePlugin({
   'process.env': env
  }),
  // 压缩 js
  new webpack.optimize.UglifyJsPlugin({
   compress: {
    warnings: false
   },
   sourceMap: true
  }),
  // 提取 css
  new ExtractTextPlugin({
   filename: utils.assetsPath('css/[name].[contenthash].css')
  }),
  // 压缩提取出来的 css
  // 可以删除来自不同组件的冗余代码
  // Compress extracted CSS. We are using this plugin so that possible
  // duplicated CSS from different components can be deduped.
  new OptimizeCSSPlugin(),
  // 将 index.html 作为入口,注入 html 代码后生成 index.html文件
  // https://github.com/ampedandwired/html-webpack-plugin
  new HtmlWebpackPlugin({
   filename: process.env.NODE_ENV === 'testing'
    ? 'index.html'
    : config.build.index,
   template: 'index.html',
   inject: true,
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
    // 更多选项 https://github.com/kangax/html-minifier#options-quick-reference
   },
   // 必须通过 CommonsChunkPlugin一致地处理多个 chunks
   chunksSortMode: 'dependency'
  }),
  // 分割公共 js 到独立的文件
  // https://webpack.js.org/guides/code-splitting-libraries/#commonschunkplugin
  new webpack.optimize.CommonsChunkPlugin({
   name: 'vendor',
   minChunks: function (module, count) {
    // node_modules中的任何所需模块都提取到vendor
    return (
     module.resource &&
     /\.js$/.test(module.resource) &&
     module.resource.indexOf(
      path.join(__dirname, '../node_modules')
     ) === 0
    )
   }
  }),
  // 将webpack runtime 和模块清单 提取到独立的文件,以防止当 app包更新时导致公共 jsd hash也更新
  // extract webpack runtime and module manifest to its own file in order to
  // prevent vendor hash from being updated whenever app bundle is updated
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest',
   chunks: ['vendor']
  }),
  // 复制静态资源
  // https://github.com/kevlened/copy-webpack-plugin
  new CopyWebpackPlugin([
   {
    from: path.resolve(__dirname, '../static'),
    to: config.build.assetsSubDirectory,
    ignore: ['.*']
   }
  ])
 ]
})

// 开启 gzip 的情况时,给 webpack plugins添加 compression-webpack-plugin 插件
if (config.build.productionGzip) {
  // webpack 压缩插件
  // https://github.com/webpack-contrib/compression-webpack-plugin
 var CompressionWebpackPlugin = require('compression-webpack-plugin')

 // 向webpackconfig.plugins中加入下方的插件
 webpackConfig.plugins.push(
  new CompressionWebpackPlugin({
   asset: '[path].gz[query]',
   algorithm: 'gzip',
   test: new RegExp(
    '\\.(' +
    config.build.productionGzipExtensions.join('|') +
    ')$'
   ),
   threshold: 10240,
   minRatio: 0.8
  })
 )
}

// 开启包分析的情况时, 给 webpack plugins添加 webpack-bundle-analyzer 插件
if (config.build.bundleAnalyzerReport) {
 // https://github.com/th0r/webpack-bundle-analyzer
 var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
 webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

其他

如果你觉得在segmentfault的代码阅读体验不好,你可以到我github上将代码clone下来看。

vue-cli-webpack-analysis

总结

这次研究webpack配置的时候,我自己跟着源码敲了一遍(很笨的方法),然后,在github和webpack官网上查使用到的插件的作用和用法。经过这一次折腾,加深对webpack的认识。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
关于document.cookie的使用javascript
Oct 29 Javascript
js中根据字数截取字符串,不能截断url
Jan 12 Javascript
Javascript检查图片大小不要让大图片撑破页面
Nov 04 Javascript
JS+CSS实现可拖动的弹出提示框
Feb 16 Javascript
JavaScript中逗号运算符介绍及使用示例
Mar 13 Javascript
javascript实现的固定位置悬浮窗口实例
Apr 30 Javascript
JavaScript实现LI列表数据绑定的方法
Aug 04 Javascript
深入理解JQuery中的事件与动画
May 18 Javascript
BootStrap按钮标签及基本样式
Nov 23 Javascript
jQuery动态产生select option下拉列表
Mar 15 Javascript
Vue中android4.4不兼容问题的解决方法
Sep 04 Javascript
9102了,你还不会移动端真机调试吗
Mar 25 Javascript
微信小程序开发之左右分栏效果的实例代码
May 20 #Javascript
微信小程序rich-text富文本用法实例分析
May 20 #Javascript
bootstrap中的导航条实例代码详解
May 20 #Javascript
详解小程序云开发数据库
May 20 #Javascript
VUE脚手架具体使用方法
May 20 #Javascript
Vue CLI2升级至Vue CLI3的方法步骤
May 20 #Javascript
解决Vue+Electron下Vuex的Dispatch没有效果问题
May 20 #Javascript
You might like
2021年最新CPU天梯图
2021/03/04 数码科技
php正则preg_replace_callback函数用法实例
2015/06/01 PHP
PHP利用DWZ.CN服务生成短网址
2019/08/11 PHP
使用git迁移Laravel项目至新开发环境的步骤详解
2020/04/06 PHP
javascript preload&lazy load
2010/05/13 Javascript
Array, Array Constructor, for in loop, typeof, instanceOf
2011/09/13 Javascript
jQuery easyui datagrid动态查询数据实例讲解
2013/02/26 Javascript
JS幻灯片可循环播放可平滑旋转带滚动导航(自写)
2013/08/05 Javascript
关闭浏览器输入框自动补齐 兼容IE,FF,Chrome等主流浏览器
2014/02/11 Javascript
控制input输入框中提示信息的显示和隐藏的方法
2014/02/12 Javascript
nodejs 提示‘xxx’ 不是内部或外部命令解决方法
2014/11/20 NodeJs
jquery实现右侧栏菜单选择操作
2016/03/04 Javascript
第九章之路径分页标签与徽章组件
2016/04/25 Javascript
Ionic2开发环境搭建教程
2020/08/20 Javascript
Angular.js ng-file-upload结合springMVC的使用教程
2017/07/10 Javascript
AngularJS 控制器 controller的详解
2017/10/17 Javascript
vue3.0 CLI - 2.2 - 组件 home.vue 的初步改造
2018/09/14 Javascript
微信小程序点击生成朋友圈分享图(遇到的坑)
2020/06/17 Javascript
vue实现把接口单独存放在一个文件方式
2020/08/13 Javascript
vue element和nuxt的使用技巧分享
2021/01/14 Vue.js
python通过imaplib模块读取gmail里邮件的方法
2015/05/08 Python
分享Pycharm中一些不为人知的技巧
2018/04/03 Python
python使用phoenixdb操作hbase的方法示例
2019/02/28 Python
Pytorch修改ResNet模型全连接层进行直接训练实例
2019/09/10 Python
50行Python代码实现视频中物体颜色识别和跟踪(必须以红色为例)
2019/11/20 Python
前端canvas水印快速制作(附完整代码)
2019/09/19 HTML / CSS
小狗电器官方商城:中国高端吸尘器品牌
2017/03/29 全球购物
英国第一的滑雪服装和装备零售商:Snow+Rock
2020/02/01 全球购物
介绍一下RMI的基本概念
2016/12/17 面试题
自荐信怎么写呢?
2013/12/09 职场文书
校园安全检查制度
2014/02/03 职场文书
四议两公开实施方案
2014/03/28 职场文书
小学见习报告
2014/10/31 职场文书
学习杨善洲同志先进事迹心得体会
2016/01/23 职场文书
MySQL三种方式实现递归查询
2022/04/18 MySQL
PYTHON 使用 Pandas 删除某列指定值所在的行
2022/04/28 Python