vue-cli中的webpack配置

原文 http://www.cnblogs.com/libin-1/p/6596810.html

版本号

vue-cli2.8.1 (终端通过vue -V可查看)

vue2.2.2

webpack2.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: {

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 extensionin loaders) {//循环遍历loadersvar loader = loaders[extension]//根据遍历获得的key(extension)来得到value(loader)    output.push({//      test:newRegExp('\\.' + 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文件    }  }functiongenerateLoaders (loader, loaderOptions) {//生成loadervar loaders = [cssLoader]// 默认是css-loaderif (loader) {// 如果参数loader存在      loaders.push({loader: loader +'-loader',options:Object.assign({}, loaderOptions, {//将loaderOptions和sourceMap组成一个对象          sourceMap: options.sourceMap        })      })    }if (options.extract) {// 如果传入的options存在extract且为truereturn 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.envplugins: [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.jsnew 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:newRegExp(//满足正则表达式的文件会被压缩'\\.(' +        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的代理urlvar app = express()//启动expressvar 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//编译成功后打印uridevMiddleware.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'//设置当前环境为productionvar ora =require('ora')//终端显示的转轮loadingvar 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()//停止loadingif (err)throw err// 在编译完成的回调函数中,在终端输出编译的文件    process.stdout.write(stats.toString({colors:true,modules:false,children:false,chunks:false,chunkModules:false    }) +'\n\n')

})

})

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 8,078评论 7 35
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,604评论 7 110
  • 写在开头 先说说为什么要写这篇文章, 最初的原因是组里的小朋友们看了webpack文档后, 表情都是这样的: (摘...
    Lefter阅读 5,229评论 4 31
  • 学习流程 参考文档:入门Webpack,看这篇就够了Webpack for React 一. 简单使用webpac...
    Jason_Zeng阅读 3,041评论 2 16
  • 我怕岁月太长,而我终将会把你遗忘。所以我想用我的方式把你嵌刻在我的生命里深一点,在深一点。 ...
    夏尔_b997阅读 306评论 0 0