上一期从零构建了一个基础版的vue-cli项目,主要介绍了loader的安装和一些配置项的用法,还给项目添加了less预处理器javascript
上一期的连接-从搭建vue-脚手架到掌握webpack配置(一.基础配置)css
本期开始引入经常使用的插件实现开发环境和生成环境会用到的一些功能,好比热插拔、css样式提取、公共模块提、取代码压缩等等html
不少插件功能是在开发环境(development)用到的可是在生产环境(production)用不到的,反之亦然。好比vue
引用官方的说法 ,区分生产和开发环境有两种方法,以下图 java
第二种方法涉及到二次封装,就像官方vue-cli构建的项目同样,分红了三个配置文件,对目前的咱们来讲比较复杂,咱们使用第一种方法,设置环境变量来区分部署环境。node
参考vue-cli生成的简单版工程(webpack-simple),咱们发现npm script写得有点奇怪jquery
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
}
复制代码
在运行webpack命令以前运行了 cross-env NODE_ENV=develpoment
和production
,这就是给环境变量赋值的过程,可是单单这样写是没法执行的,咱们须要安装一个插件——cross-env
webpack
npm install --save cross-env
复制代码
这样咱们就能够在以后运行在node环境的js 文件中访问到这些环境变量,经过process.env
对象还能拿到package.json里面的配置信息,这就涉及到node的知识了,很少说。web
const env = process.env.NODE_ENV
//获取工程的版本号
const version = process.env.npm_package_version
复制代码
简单点写,把环境变量的判断直接放到webpack.config.js文件的最下面vue-cli
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry:{
app:'./src/main.js'
},
//...
}
/**
* 生成生产代码的时候才触发
*/
if (process.env.NODE_ENV === 'production') {
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
])
}
复制代码
若是之后额外的配置项愈来愈多的话,像上面这样写是不太好合并配置项的,到最后仍是要抽离出另外一个js文件装载新增或重写的配置项,用webpack-merge中间件合并配置对象。
webpack.DefinePlugin插件是设置全局常量的插件,要记住!赋值的时候记得写成'"production"'
, 官方对DefinePlugin插件 是这么说的
注意,由于这个插件直接执行文本替换,给定的值必须包含字符串自己内的实际引号。一般,有两种方式来达到这个效果,使用 '"production"', 或者使用 JSON.stringify('production')。
以前根目录下index.html要咱们本身引入js资源地址,有新的资源都要手动引入,很麻烦,这时候就会用到HtmlWebpackPlugin 插件,按照index.html做为模板在dist目录下生成带上全部资源的html 文件。
npm install --save-dev html-webpack-plugin
复制代码
先经过require引入插件,而后在输出对象里面添加plugins属性,数据值类型是数组,数组成员new [插件]()
添加插件就行。每一个插件都有本身的配置项和规范,能够查 npmjs 或者 他们的官方文档
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
module.exports = {
entry:{
app:'./src/main.js'
},
output:{
path:path.resolve(__dirname,'./dist'),
filename:"js/[name].js",
},
module:{
rules:[
//...
]
},
plugins:[
new HtmlWebpackPlugin({
filename:'index.html',
title:'vue demo',
template:'./index.html',
})
],
externals:{
'jquery':'window.jQuery'
}
}
复制代码
filename
生成的html的文件名,不填就默认是原文件名title
title标签的内容template
html模板地址,这里咱们用我上一期建在跟目录的index.html这里有前辈对HtmlWebpackPlugin的详细说明文章
index.html的内容要改一改了,由于webpack打包完以后自动添加资源地址到html文件里,因此咱们要删掉本来写上去的script标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue demo</title>
</head>
<body>
<div id="app">
</div>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js"></script>
</body>
</html>
复制代码
有人可能会奇怪,这里为何加了一个cdn的jQuery,由于我要在这里带过一个知识点:有时候咱们会有用到cdn加速的库资源,可是不知道怎么在工程中使用。
很简单咱们在html模板中直接引入,而后在webpack.config.js配置中加一项“外部引入”(externals)
// webpack.config.js
externals:{
'jquery':'window.jQuery'
}
//app.vue中引入
import $ from 'jquery'
复制代码
使用热替换以前固然要先有一个web服务器环境啦,安装webpack-dev-server
npm install --save-dev webpack-dev-server
复制代码
webpack-dev-server实际上是一个独立的插件,可是webpack内置了它的配置项,属性devServer
对应的就是它的配置项。
module.exports = {
entry:{
app:'./src/main.js'
},
output:{
path:path.resolve(__dirname,'./dist'),
filename:"js/[name].js",
},
devServer:{
contentBase:"./dist"
}
}
复制代码
端口地址什么的都默认 http://localhost:8080/ ,就设置了跟资源目录地址contentBase。 想更深刻的去配置能够看官方文档 dev-server。我还真没认真看过,嘻嘻。
热替换就是开发的过程当中修改文件内容以后不用频繁刷新页面,修改会自动同步到浏览器中,webpack内部已经有这份插件了,不用安装直接都用就能够。在plugins添加一项 new webpack.HotModuleReplacementPlugin()
就ok了
plugins:[
new HtmlWebpackPlugin({
filename:'index.html',
title:'vue demo',
template:'./index.html',
}),
new webpack.HotModuleReplacementPlugin()
]
复制代码
改一下npm scripts
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
}
复制代码
运行 npm run dev
,热部署搞定
以上是开发环境要用到的插件,下面就是生成环境用到的插件了
若是不提取css样式,全部的.css文件和vue内的style都会以style标签的形式被添加到页面的head里面,不利于资源的缓存并且下降了页面的加载速度。
好的,就用extract-text-webpack-plugin插件吧,老规矩安装一下
npm install extract-text-webpack-plugin --save-dev
复制代码
在使用css相关loader以前先用本插件过滤一遍
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
// other options...
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader' // <- 这是vue-loader的依赖
}),
//用了less或者sass的地方都要用上哦
'less': ExtractTextPlugin.extract({
use:[
'css-loader',
'less-loader'
],
fallback:'vue-style-loader'
})
}
}
}
]
},
plugins: [
new ExtractTextPlugin("styles/style.css")
]
}
复制代码
vue内部的style须要先抽取出来,因此要在fallback属性上添加预先的加载器 'vue-style-loader','vue-style-loader'是vue-loader自带的哦,若是运行时报错的话那就手动install一下他吧。
我通常的习惯是把外部引入的css文件认为是能够复用的,而vue内的style是每一个页面都不同的要另外生成的,因此我建了两ExtractTextPlugin实例分别抽取样式到两个文件里。
const path = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const ExtractRootCss = new ExtractTextPlugin({filename:'styles/root.css',allChunks:false});
const ExtractVueCss = new ExtractTextPlugin({filename:'styles/[name]/style.css',allChunks:true});
module.exports = {
//other options...
module:{
rules:[
//...
{
test:/\.css$/,
//这里用的ExtractRootCss
use:ExtractRootCss.extract({
fallback:'style-loader',
use:['css-loader']
})
},
{
test:/\.less$/,
//这里用的ExtractRootCss
use:ExtractRootCss.extract({
fallback:'style-loader',
use:[
'css-loader',
'less-loader'
]
})
},
{
test:/\.vue$/,
loader:'vue-loader',
options:{
loaders:{
//这里用的ExtractVueCss
'css': ExtractVueCss.extract({
use: 'css-loader',
fallback: 'vue-style-loader' // <- 这是vue-loader的依赖,因此若是使用npm3,则不须要显式安装
}),
//这里用的ExtractVueCss
'less':
ExtractVueCss.extract({
use:[
'css-loader',
'less-loader'
],
fallback:'vue-style-loader'
})
},
}
},
]
},
plugins:[
new HtmlWebpackPlugin({
filename:'index.html',
title:'vue demo',
template:'./index.html',
}),
ExtractRootCss,//填入插件实例,复用的css
ExtractVueCss,//记得按顺序填入,vue内的css
new webpack.HotModuleReplacementPlugin(),
]
}
复制代码
这就是ExtractTextPlugin插件生成多个文件的方法。你也能够按照本身的习惯去配置。
在多页面或者多入口的时候(entry设了不仅一个),不一样的模块(chunks)会屡次引入同样的资源模块(module,也就是import引入的js文件),还有vue等库的代码,以上这些复用的代码最好是能够独立出来,一方面方便缓存,一方面减小包的体积。
CommonsChunkPlugin插件就是解决这一问题的,它从属于webpack.optimize对象因此也是不用安装的。具体使用以下
new webpack.optimize.CommonsChunkPlugin({
name: 'vender',
minChunks:2
})
复制代码
minChunks
参数能够是number类型,填2 就是说有2个chunk以上用到的公共块就会被打包的vender.js里面。minChunks也能够传一个方法,返回值是boolean
类型.
(chunk能够简单理解为entry属性设置的入口而生成的整条关系树,因此到目前为止本项目也只有一个chunk,就是'app',固然插件生成的vender也是一个chunk。对初学者来讲就这样理解吧,用多了天然会有概念)
既然只有一个chunk 那就先抽取公用库中的代码吧,如vue包中的代码。把代码放到生产环境判断里面哦~
/*生成生产代码的时候才触发*/
if (process.env.NODE_ENV === 'production') {
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
//抽取从node_modules引入的模块,如vue
new webpack.optimize.CommonsChunkPlugin({
name: 'vender',
minChunks:function(module,count){
var sPath = module.resource;
// console.log(sPath,count);
//匹配 node_modules文件目录
return sPath &&
/\.js$/.test(sPath) &&
sPath.indexOf(
path.join(__dirname, 'node_modules')
) === 0
}
})
])
}
复制代码
这是中文文档上的介绍 commons-chunk-plugin
这是一个好心人总结的各类配置状况下打包的结果 segmentfault.com/a/119000000…
由于重构和压缩后的代码不利于debug,因此咱们先要开启source map功能,在webpack配置里面添加一项devtool
,以下
module.exports = {
//entry: ...
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
}
复制代码
eval-source-map
是开发环境用的源码映射,source-map
是生成环境用的源码映射
官方对 devtool的介绍在这里
阮一峰老师对 source map 的介绍在这里
css文件在 build(抽取和装载)的同时已经进行了简单的压缩,因此下面主要是对js代码的压缩,也就是经常的UglifyJs(丑化js),webpack自带了UglifyJsPlugin插件,在plugins上启用就行。
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,//开启源码映射
compress: {
warnings: false//去到警告
}
}),
复制代码
可是以上的用法是webpack1.0遗留下来的,用的旧版的UglifyJs,他的使用说明也在wepack1.0的文档里。你能够有手动安装uglifyjs-webpack-plugin,引入最新的UglifyJs
/* npm install -save-dev uglifyjs-webpack-plugin */
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: true
})
复制代码
webpack3.0中文文档对该插件的说明 在这里
官方文档的介绍 在这里
loader-options-plugin 和其余插件不一样。它的用途是帮助人们从 webpack 1 迁移至 webpack 2。官方说明
new webpack.LoaderOptionsPlugin({
minimize: true
}),
复制代码
好了到目前为止大部分会用到的插件都引入到了webpack配置里面,构建一下试试。
完整webpack.config.js的代码在这里 pan.baidu.com/s/1jKnDSYa
npm run dev
复制代码
npm run build
复制代码
发现uglifyJs报错,是由于咱们没有配置babel的翻译器和编译规则,篇幅有限babel的配置说明放到下一期。
解决方法:在根目录下建立文件.babelrc
,内容以下
{
"presets": [
["env", {
"modules": false
}]
]
}
复制代码
安装babel-preset-env,npm install --save-dev babel-preset-env
而后再build,没问题了
打包后的目录结构以下
想要深刻了解每一个插件的具体用法,定制本身的需求必定要多点去参考文档和资料。为了方便你们我已经在教程中每个插件的下面给了大量的连接,能够说省去了你们百度的时间,忽然感受本身好细心。
官方文档也不须要所有都看,用到什么看什么,要什么功能配置就重点看那部分就好,等到有时间再简要的过一遍文档。
到目前为止,整个工程能够说彻底可用了。样式抽离,公共提取,压缩都用到了,对比一下
vue init webpack-simple project-name
构建的简单工程,会发现咱们比它的功能还完整,有没有一点成就感呢?
很惋惜,没想到讲插件用了这么长的篇幅,仍是没有提到postcss和babel的配置,下一期开始简要提一下这些,而后咱们继续优化构建过程,让他能够适应多入口多页面的开发。想要了解之后的内容能够关注哦~~
第三期已更新:从搭建vue-脚手架到掌握webpack配置(三.多页面构建)