vue-cli中webpack配置解析

版本号

vue-cli 2.8.1 (终端通过vue -V 可查看)

vue 2.2.2

webpack 2.2.1

目录结构

├── README.md
├── build
│   ├── build.js
│   ├── check-versions.js
│   ├── dev-client.js
│   ├── dev-server.js
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   └── webpack.prod.conf.js
├── config
│   ├── dev.env.js
│   ├── index.js
│   └── prod.env.js
├── index.html
├── package.json
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── Hello.vue
│   └── main.js
└── static

webpack配置

主要对build目录下的webpack配置做详细分析

webpack.base.conf.js

入口文件entry
entry: {
  app: ‘.src/main.js‘
}
输出文件output

config的配置在config/index.js文件中

output: {
  path: config.build.assetsRoot, //导出目录的绝对路径
  filename: ‘[name].js‘, //导出文件的文件名
  publicPath: process.env.NODE_ENV === ‘production‘? config.build.assetsPublicPath : config.dev.assetsPublicPath //生产模式或开发模式下html、js等文件内部引用的公共路径
}
文件解析resolve

主要设置模块如何被解析。

resolve: {
  extensions: [‘.js‘, ‘.vue‘, ‘.json‘], //自动解析确定的拓展名,使导入模块时不带拓展名
  alias: {   // 创建import或require的别名
    ‘vue$‘: ‘vue/dist/vue.esm.js‘,
    ‘@‘: resolve(‘src‘)
  }
}
模块解析module

如何处理项目不同类型的模块。

module: {
  rules: [
    {
      test: /\.vue$/, // vue文件后缀
      loader: ‘vue-loader‘, //使用vue-loader处理
      options: vueLoaderConfig //options是对vue-loader做的额外选项配置
    },
    {
      test: /\.js$/, // js文件后缀
      loader: ‘babel-loader‘, //使用babel-loader处理
      include: [resolve(‘src‘), resolve(‘test‘)] //必须处理包含src和test文件夹
    },
    {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, //图片后缀
      loader: ‘url-loader‘, //使用url-loader处理
      query: {  // query是对loader做额外的选项配置
        limit: 10000, //图片小于10000字节时以base64的方式引用
        name: utils.assetsPath(‘img/[name].[hash:7].[ext]‘) //文件名为name.7位hash值.拓展名
      }
    },
    {
      test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, //字体文件
      loader: ‘url-loader‘, //使用url-loader处理
      query: {
        limit: 10000,  //字体文件小于1000字节的时候处理方式
        name: utils.assetsPath(‘fonts/[name].[hash:7].[ext]‘) //文件名为name.7位hash值.拓展名
      }
    }
  ]
}

注: 关于query 仅由于兼容性原因而存在。请使用 options 代替。

webpack.dev.conf.js

开发环境下的webpack配置,通过merge方法合并webpack.base.conf.js基础配置

var merge = require(‘webpack-merge‘)
var baseWebpackConfig = require(‘./webpack.base.conf‘)
module.exports = merge(baseWebpackConfig, {})
模块配置
module: {
  //通过传入一些配置来获取rules配置,此处传入了sourceMap: false,表示不生成sourceMap
  rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
}

util.styleLoaders中的配置如下

exports.styleLoaders = function (options) {
  var output = [] //定义返回的数组,数组中保存的是针对各类型的样式文件的处理方式
  var loaders = exports.cssLoaders(options) // 调用cssLoaders方法返回各类型的样式对象(css: loader)
  for (var extension in loaders) {  //循环遍历loaders
    var loader = loaders[extension] //根据遍历获得的key(extension)来得到value(loader)
    output.push({     //
      test: new RegExp(‘\\.‘ + extension + ‘$‘), // 处理的文件类型
      use: loader  //用loader来处理,loader来自loaders[extension]
    })
  }
  return output
}

上面的代码中调用了exports.cssLoaders(options),用来返回针对各类型的样式文件的处理方式,具体实现如下

exports.cssLoaders = function (options) {
  options = options || {}

  var cssLoader = {
    loader: ‘css-loader‘,
    options: {  //options是loader的选项配置
      minimize: process.env.NODE_ENV === ‘production‘, //生成环境下压缩文件
      sourceMap: options.sourceMap  //根据参数是否生成sourceMap文件
    }
  }
  function generateLoaders (loader, loaderOptions) {  //生成loader
    var loaders = [cssLoader] // 默认是css-loader
    if (loader) { // 如果参数loader存在
      loaders.push({
        loader: loader + ‘-loader‘,
        options: Object.assign({}, loaderOptions, { //将loaderOptions和sourceMap组成一个对象
          sourceMap: options.sourceMap
        })
      })
    }
    if (options.extract) { // 如果传入的options存在extract且为true
      return ExtractTextPlugin.extract({  //ExtractTextPlugin分离js中引入的css文件
        use: loaders,  //处理的loader
        fallback: ‘vue-style-loader‘ //没有被提取分离时使用的loader
      })
    } else {
      return [‘vue-style-loader‘].concat(loaders)
    }
  }
  return {  //返回css类型对应的loader组成的对象 generateLoaders()来生成loader
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders(‘less‘),
    sass: generateLoaders(‘sass‘, { indentedSyntax: true }),
    scss: generateLoaders(‘sass‘),
    stylus: generateLoaders(‘stylus‘),
    styl: generateLoaders(‘stylus‘)
  }
}
插件配置
plugins: [
  new webpack.DefinePlugin({ // 编译时配置的全局变量
    ‘process.env‘: config.dev.env //当前环境为开发环境
  }),
  new webpack.HotModuleReplacementPlugin(), //热更新插件
  new webpack.NoEmitOnErrorPlugin(), //不触发错误,即编译后运行的包正常运行
  new HtmlWebpackPlugin({  //自动生成html文件,比如编译后文件的引入
    filename: ‘index.html‘, //生成的文件名
    template: ‘index.html‘, //模板
    inject: true
  }),
  new FriendlyErrorsPlugin() //友好的错误提示
]

webpack.prod.conf.js

生产环境下的webpack配置,通过merge方法合并webpack.base.conf.js基础配置

module的处理,主要是针对css的处理

同样的此处调用了utils.styleLoaders

module: {
  rules: utils.styleLoaders({
    sourceMap: config.build.productionSourceMap,
    extract: true
  })
}
输出文件output
output: {
  //导出文件目录
  path: config.build.assetsRoot,
  //导出的文件名
  filename: utils.assetsPath(‘js/[name].[chunkhash].js‘),
  //非入口文件的文件名,而又需要被打包出来的文件命名配置,如按需加载的模块
  chunkFilename: utils.assetsPath(‘js/[id].[chunkhash].js‘)
}
插件plugins
var path = require(‘path‘)
var utils = require(‘./utils‘)
var webpack = require(‘webpack‘)
var config = require(‘../config‘)
var merge = require(‘webpack-merge‘)
var baseWebpackConfig = require(‘./webpack.base.conf‘)
var CopyWebpackPlugin = require(‘copy-webpack-plugin‘)
var HtmlWebpackPlugin = require(‘html-webpack-plugin‘)
var ExtractTextPlugin = require(‘extract-text-webpack-plugin‘)
var OptimizeCSSPlugin = require(‘optimize-css-assets-webpack-plugin‘)
var env = config.build.env
plugins: [
  new webpack.DefinePlugin({
    ‘process.env‘: env //配置全局环境为生产环境
  }),
  new webpack.optimize.UglifyJsPlugin({ //js文件压缩插件
    compress: {  //压缩配置
      warnings: false  // 不显示警告
    },
    sourceMap: true //生成sourceMap文件
  }),
  new ExtractTextPlugin({ //将js中引入的css分离的插件
    filename: utils.assetsPath(‘css/[name].[contenthash].css‘) //分离出的css文件名
  }),
  //压缩提取出的css,并解决ExtractTextPlugin分离出的js重复问题(多个文件引入同一css文件)
  new OptimizeCSSPlugin(),
  //生成html的插件,引入css文件和js文件
  new HtmlWebpackPlugin({
    filename: config.build.index, //生成的html的文件名
    template: ‘index.html‘, //依据的模板
    inject: true, //注入的js文件将会被放在body标签中,当值为‘head‘时,将被放在head标签中
    minify: {  //压缩配置
      removeComments: true, //删除html中的注释代码
      collapseWhitespace: true,  //删除html中的空白符
      removeAttributeQuotes: true  //删除html元素中属性的引号
    },
    chunksSortMode: ‘dependency‘ //按dependency的顺序引入
  }),
  //分离公共js到vendor中
  new webpack.optimize.CommonsChunkPlugin({
    name: ‘vendor‘,  //文件名
    minChunks: functions(module, count) { // 声明公共的模块来自node_modules文件夹
      return (module.resource && /\.js$/.test(module.resource) && module,resource.indexOf(path.join(__dirname, ‘../node_modules‘)) === 0)
    }
  }),
  //上面虽然已经分离了第三方库,每次修改编译都会改变vendor的hash值,导致浏览器缓存失效。原因是vendor包含了webpack在打包过程中会产生一些运行时代码,运行时代码中实际上保存了打包后的文件名。当修改业务代码时,业务代码的js文件的hash值必然会改变。一旦改变必然会导致vendor变化。vendor变化会导致其hash值变化。
  //下面主要是将运行时代码提取到单独的manifest文件中,防止其影响vendor.js
  new webpack.optimize.CommonsChunkPlugin({
    name: ‘mainifest‘,
    chunks: [‘vendor‘]
  }),
  // 复制静态资源,将static文件内的内容复制到指定文件夹
  new CopyWebpackPlugin([{
    from: path.resolve(__dirname, ‘../static‘),
    to: config.build.assetsSubDirectory,
    ignore: [‘.*‘]  //忽视.*文件
  }])
]
额外配置
if (config.build.productionGzip) { //配置文件开启了gzip压缩

  //引入压缩文件的组件,该插件会对生成的文件进行压缩,生成一个.gz文件
  var CompressionWebpackPlugin = require(‘compression-webpack-plugin‘) 

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: ‘[path].gz[query]‘, //目标文件名
      algorithm: ‘gzip‘, //使用gzip压缩
      test: new RegExp( //满足正则表达式的文件会被压缩
        ‘\\.(‘ +
        config.build.productionGzipExtensions.join(‘|‘) +
        ‘)$‘
      ),
      threshold: 10240, //资源文件大于10240B=10kB时会被压缩
      minRatio: 0.8 //最小压缩比达到0.8时才会被压缩
    })
  )
}

npm run dev

有了上面的配置之后,下面看看运行命令npm run dev发生了什么

package.json文件中定义了dev运行的脚本

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

当运行npm run dev命令时,实际上会运行dev-server.js文件

该文件以express作为后端框架

// nodejs环境配置
var config = require(‘../config‘)
if (!process.env.NODE_ENV) {
  process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}
var opn = require(‘opn‘) //强制打开浏览器
var path = require(‘path‘)
var express = require(‘express‘)
var webpack = require(‘webpack‘)
var proxyMiddleware = require(‘http-proxy-middleware‘) //使用代理的中间件
var webpackConfig = require(‘./webpack.dev.conf‘) //webpack的配置

var port = process.env.PORT || config.dev.port //端口号
var autoOpenBrowser = !!config.dev.autoOpenBrowser //是否自动打开浏览器
var proxyTable = config.dev.proxyTable //http的代理url

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

//webpack-dev-middleware的作用
//1.将编译后的生成的静态文件放在内存中,所以在npm run dev后磁盘上不会生成文件
//2.当文件改变时,会自动编译。
//3.当在编译过程中请求某个资源时,webpack-dev-server不会让这个请求失败,而是会一直阻塞它,直到webpack编译完毕
var devMiddleware = require(‘webpack-dev-middleware‘)(compiler, {
  publicPath: webpackConfig.output.publicPath,
  quiet: true
})

//webpack-hot-middleware的作用就是实现浏览器的无刷新更新
var hotMiddleware = require(‘webpack-hot-middleware‘)(compiler, {
  log: () => {}
})
//声明hotMiddleware无刷新更新的时机:html-webpack-plugin 的template更改之后
compiler.plugin(‘compilation‘, function (compilation) {
  compilation.plugin(‘html-webpack-plugin-after-emit‘, function (data, cb) {
    hotMiddleware.publish({ action: ‘reload‘ })
    cb()
  })
})

//将代理请求的配置应用到express服务上
Object.keys(proxyTable).forEach(function (context) {
  var options = proxyTable[context]
  if (typeof options === ‘string‘) {
    options = { target: options }
  }
  app.use(proxyMiddleware(options.filter || context, options))
})

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

// 应用devMiddleware中间件
app.use(devMiddleware)
// 应用hotMiddleware中间件
app.use(hotMiddleware)

// 配置express静态资源目录
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static(‘./static‘))

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

//编译成功后打印uri
devMiddleware.waitUntilValid(function () {
  console.log(‘> Listening at ‘ + uri + ‘\n‘)
})
//启动express服务
module.exports = app.listen(port, function (err) {
  if (err) {
    console.log(err)
    return
  }
  // 满足条件则自动打开浏览器
  if (autoOpenBrowser && process.env.NODE_ENV !== ‘testing‘) {
    opn(uri)
  }
})

npm run build

由于package.json中的配置,运行此命令后会执行build.js文件

process.env.NODE_ENV = ‘production‘ //设置当前环境为production
var ora = require(‘ora‘) //终端显示的转轮loading
var rm = require(‘rimraf‘)  //node环境下rm -rf的命令库
var path = require(‘path‘)  //文件路径处理库
var chalk = require(‘chalk‘)  //终端显示带颜色的文字
var webpack = require(‘webpack‘)
var config = require(‘../config‘)
var webpackConfig = require(‘./webpack.prod.conf‘) //生产环境下的webpack配置

// 在终端显示ora库的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) {
    spinner.stop() //停止loading
    if (err) throw err

    // 在编译完成的回调函数中,在终端输出编译的文件
    process.stdout.write(stats.toString({
      colors: true,
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }) + ‘\n\n‘)
  })
})

转载原网站https://www.cnblogs.com/libin-1/p/6596810.html

原文地址:https://www.cnblogs.com/aidixie/p/10118004.html

时间: 2024-10-10 13:02:32

vue-cli中webpack配置解析的相关文章

vue UI 告别webpack配置

目录 vue UI 告别webpack配置 开始体验 创建项目 项目细节 1. 插件 2. 依赖 3. 配置 4. 任务 总结 vue UI 告别webpack配置 vue-cli 3.0 的候选版本也已经发布多时了.vue-cli 3.0 版本为我们提供了集 创建.管理.分析 为一体的可视化界面vue ui,妈妈再也不用担心我不懂配置啦~让我们来一起尝尝鲜吧~ #安装最新版的vue-cli npm install -g @vue/cli #yarn/npm 安装(二选一) yarn globa

vue cli中环境变量和模式

环境变量配置 环境变量可以在以下文件中配置: .env # 在所有的环境中被载入 .env.local # 在所有的环境中被载入,但会被 git 忽略 .env.[mode] # 只在指定的模式中被载入 .env.[mode].local # 只在指定的模式中被载入,但会被 git 忽略 (.local优先于.env生效) 文件内部使用键值对的方式对变量进行配置 被载入的变量将会对 vue-cli-service 的所有命令.插件和依赖可用,同时为一个特定模式准备的环境文件的 (例如 .env.

vue-cli脚手架中webpack配置基础文件详解

一.前言 vue-cli是构建vue单页应用的脚手架,输入一串指定的命令行从而自动生成vue.js+wepack的项目模板.这其中webpack发挥了很大的作用,它使得我们的代码模块化,引入一些插件帮我们完善功能可以将文件打包压缩,图片转base64等.后期对项目的配置使得我们对于脚手架自动生成的代码的理解更为重要,接下来我将基于webpack3.6.0版本结合文档将文件各个击破,纯干料.重点章节点击查看:package.json:config/index.js:webpack.base.con

vue cli 3.x 配置使用 sourceMap

项目使用vue cli 3.x搭建,没有了配置文件,如何更方便的查找到对应的scss文件,配置项目支持sourceMap方式? 分二步走: 1.项目根目录(不是src目录,不要搞错了)添加vue.config.js 2.vue.config.js内容如下: module.exports = { css: { sourceMap: true, // 开启 CSS source maps } } 记得要停止项目,再重新运行项目 npm run serve 不然你以为没有生效,以为我在忽悠你,根本没作

vue-cli 脚手架中 webpack 配置基础文件详解

一.前言 vue-cli是构建vue单页应用的脚手架,输入一串指定的命令行从而自动生成vue.js+wepack的项目模板.这其中webpack发挥了很大的作用,它使得我们的代码模块化,引入一些插件帮我们完善功能可以将文件打包压缩,图片转base64等.后期对项目的配置使得我们对于脚手架自动生成的代码的理解更为重要,接下来我将基于webpack3.6.0版本结合文档将文件各个击破,纯干料. 二.主体结构 1. package.json 项目作为一个大家庭,每个文件都各司其职.package.js

rem的在vue项目中使用配置,,浏览器的兼容性之Mate标签

在vue中配置rem 位置:在APP.vue的script中,在export default之外 (()=>{ let winW = document.documentElement.clientWidth, desW = 1440, htmlFont = winW / desW * 100; window.htmlFont = htmlFont; document.documentElement.style.fontSize = htmlFont + 'px'; })() 浏览器的兼容性之Ma

Vue-axios 在vue cli中封装

common/post.js import axios from 'axios' // 引入axios import qs from 'qs' // 引入qs axios.defaults.baseURL = '/apis' //请求地址的域名(此处使用了代理所以直接填/apis // 拦截响应response,进行错误处理 axios.interceptors.response.use(function (response) { // 成功处理 // code处理 response.code

Seajs框架中路径配置解析

index.html页面: 公用配置文件configuration.js:

@vue/cli 3 安装搭建及 webpack 配置

首先卸载旧版1 npm uninstall vue-cli -g //or 2 yarn global remove vue-cli 再次安装 1 npm install -g @vue/cli 2 //or 3 yarn global add @vue/cl 查看版本 vue --version //or vue -V 创建项目vue create  my-project //项目名// Windows 上通过 minTTY 使用 Git Bash,交互提示符并不工作.  //你必须通过