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 相关文章推荐
JavaScript中的对象序列化介绍
Dec 30 Javascript
javascript事件模型实例分析
Jan 30 Javascript
javascript 使用for循环时该注意的问题-附问题总结
Aug 19 Javascript
JS验证邮件地址格式方法小结
Dec 01 Javascript
使用JQuery实现智能表单验证功能
Mar 08 Javascript
jQuery Easyui加载表格出错时在表格中间显示自定义的提示内容
Dec 08 Javascript
Bootstrap实现提示框和弹出框效果
Jan 11 Javascript
Angularjs自定义指令实现分页插件(DEMO)
Sep 16 Javascript
element ui分页多选,翻页记忆的实例
Sep 03 Javascript
使用localStorage替代cookie做本地存储
Sep 25 Javascript
Vue使用NProgress的操作过程解析
Oct 10 Javascript
多页vue应用的单页面打包方法(内含打包模式的应用)
Jun 11 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
用 php 编写的日历
2006/10/09 PHP
国外比较好的几个的Php开源建站平台小结
2010/04/22 PHP
Thinkphp的volist标签嵌套循环使用教程
2014/07/08 PHP
php使用number_format函数截取小数的方法分析
2016/05/27 PHP
thinkphp3.2.3 分页代码分享
2016/07/28 PHP
thinkPHP5框架设置404、403等http状态页面的方法
2018/06/05 PHP
jquery放大镜效果超漂亮噢
2013/11/15 Javascript
jquery.ui.draggable中文文档(原文翻译)
2013/11/15 Javascript
一个JavaScript的求爱小特效
2014/05/09 Javascript
jQuery实现瀑布流的取巧做法分享
2015/01/12 Javascript
超赞的动手创建JavaScript框架的详细教程
2015/06/30 Javascript
js实现左侧网页tab滑动门效果代码
2015/09/06 Javascript
jQuery实现二级下拉菜单效果
2016/01/05 Javascript
XMLHttpRequest Level 2 使用指南
2016/08/26 Javascript
基于Angularjs+mybatis实现二级评论系统(仿简书)
2017/02/13 Javascript
Angular.js基础学习之初始化
2017/03/10 Javascript
微信小程序手势操作之单触摸点与多触摸点
2017/03/10 Javascript
简单谈谈关于Angular Cli打包的事
2017/09/05 Javascript
详细分析单线程JS执行问题
2017/11/22 Javascript
vue axios基于常见业务场景的二次封装的实现
2018/09/21 Javascript
Nuxt.js SSR与权限验证的实现
2018/11/21 Javascript
一篇文章,教你学会Vue CLI 插件开发
2019/04/17 Javascript
js实现点赞按钮功能的实例代码
2020/03/06 Javascript
[06:44]2018DOTA2亚洲邀请赛4.5 SOLO赛 MidOne vs Sumail
2018/04/06 DOTA
Python解析网页源代码中的115网盘链接实例
2014/09/30 Python
Pyqt5如何让QMessageBox按钮显示中文示例代码
2019/04/11 Python
用scikit-learn和pandas学习线性回归的方法
2019/06/21 Python
Python 3.8 新功能全解
2019/07/25 Python
解决Python发送Http请求时,中文乱码的问题
2020/04/30 Python
Python爬虫基于lxml解决数据编码乱码问题
2020/07/31 Python
区分python中的进程与线程
2020/08/13 Python
活动总结新闻稿
2014/08/30 职场文书
2015年前台个人工作总结
2015/04/03 职场文书
JS创建或填充任意长度数组的小技巧汇总
2021/10/24 Javascript
MYSQL 表的全面总结
2021/11/11 MySQL
Python可变集合和不可变集合的构造方法大全
2021/12/06 Python