今天在慕课网里学习了webpack深入与实战的课程,收获很多。因为现在webpack已经是2.0的版本了,中间入了一些坑不过都一一解决了。具体的可以查看webpake2.0的中文文档。
webpack2.0的中文文档 : 感谢大牛们的无私奉献,我找到工作一定给你们赞助。
以下是学习笔记的整合。
webpack一个简单的实例
第一步:初始化npm,下载webpack,html-webpack-plugin等插件
html-webpack-plugin:npm官网上这个插件的文档,这个插件怎么用,以及它有哪些属性上面都解释的很清楚。
我的文件目录
第二步:在根目录新建一个webpack.config.js的文件,用来配置webpack打包时的一些必要信息。
// 模块引用
var path = require('path');
var webpackHtmlPlugin = require('html-webpack-plugin');
module.exports = {
// 入口文件(这里传入的是一个对象,打包后会分别生成两个js文件)
entry: {
main : './src/script/main.js',
base : './src/script/base.js'
},
// 出口文件
output: {
path: path.resolve(__dirname,'dist'),
//分别会生成两个js文件,都是以名字+hash值的形式命名。
filename: 'js/[name]-[hash].js'
},
// 注意:在path里所有输出的文件目标路径,必须是绝对路径(这里使用node.js的path模块);
// 插件
plugins : [
// 初始化插件,这个插件会为我们自动生成一个已经插入好js脚本文件的html文件。
new webpackHtmlPlugin({
// 指定生成的html文件的名字
filename : 'index-[hash].html',
//生成的文件以根目录下的index.html为模板
template : 'index.html',
//指定生成的js文件是在head里还是在body里面,不写默认在body里面
inject : 'head'
})
]
};
- ==注意==:有个地方困惑了很久,一开始是按照官方文档来写,在output的path的指定了如下路径,
output: {
path: './dist',
filename: 'js/[name]-[hash].js'
}
- 不论怎么试都报错,给出的原因是./dist不是一个绝对路径。后来才知道,path里面只可以使用绝对路径。解决的方法有两种,推荐我上面写的示例代码,用node.js的path模块,在nodejs里__dirname代表根目录。另一种解决方式是把路径写在filename里面。
output: {
path: __dirname,
filename: './dist/js/[name]-[hash].js'
}
- 这样写不太好,因为所有生成的文件都会在./dist/js/这个文件夹里面,我们还有要依赖html-webpack-plugin插件为我们自动生成一个已经插入了js脚本的index文件,这样的话,包括index.html在内的所有文件都会在同一个文件夹里面。
第三步 全部完成好后在命令行输入webpack即可。
- 得到webpack为我们自动生成的脚本文件,和已经插入脚本文件的index.html文件,并且他们并不在同一个文件夹中。
- 再把原index.html文件和为我们自动生成的index+hash值.html的文件做一个对比。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>哈哈哈</p>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="js/main-696a2dbabb5a795721ca.js"></script>
<script type="text/javascript" src="js/base-696a2dbabb5a795721ca.js"></script>
</head>
<body>
<p>哈哈哈</p>
</body>
</html>
- 会发现生成的文件是基于原文件的内容且自动为我们插入了脚本文件。
补充:我们可以在package.json里给webpack指定一些参数。使用webpack打包的时候在命令行就能看到这些参数内容了。
- 在scripts里指定webpack和webpack.config.js文件,我们要看到打包的过程,打包的模块,字体彩色,打包的原因等。
"scripts": {
"webpack" : "webpack --config webpack.config.js --progress --display-modules --colors --display-reasons"
}
- 配置好后输入 npm run webpack 即可。
生成项目中的html页面文件
文件结构
实例代码
// 模块引用
var path = require('path');
var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 入口文件
entry: {
'main' : './src/script/main.js',
'a' : './src/script/a.js',
'b' : './src/script/b.js',
'c' : './src/script/c.js',
'd' : './src/script/d.js'
},
// 出口文件
output: {
path: path.resolve(__dirname,'dist'),
filename: 'js/[name].js',
// 给所有输出文件加上公共的地址头,满足上线要求。
publicPath : 'http://kuma.com/'
},
// 注意: 在path里所有输出的文件目标路径,必须是绝对路径(使用node.js的path模块);
module: {
loaders: [
{
test: /\.hbs$/,
loader: 'handlebars-loader'
},
]
},
// 插件
plugins : [
// 初始化插件,这个插件会为我们自动生成一个已经插入好js脚本文件的html文件。
new htmlWebpackPlugin({
// 指定生成的html文件的名字
filename : 'a.html',
//生成的文件以根目录下的index.html为模板
template : 'index.html',
// 定义html文件中的title
title : '我是a',
// 打包压缩
minify: {
// 删除注释
removeComments : true,
// 删除空格
collapseInlineTagWhitespace : true,
collapseWhitespace : true
},
chunks: ['main','a']
}),
new htmlWebpackPlugin({
// 指定生成的html文件的名字
filename : 'b.html',
//生成的文件以根目录下的index.html为模板
template : 'index.html',
// 定义html文件中的title
title : '我是b',
// 打包压缩
minify: {
// 删除注释
removeComments : true,
// 删除空格
collapseInlineTagWhitespace : true,
collapseWhitespace : true
},
chunks: ['main','b']
}),
new htmlWebpackPlugin({
// 指定生成的html文件的名字
filename : 'c.html',
//生成的文件以根目录下的index.html为模板
template : 'index.html',
// 定义html文件中的title
title : '我是c',
// 打包压缩
minify: {
// 删除注释
removeComments : true,
// 删除空格
collapseInlineTagWhitespace : true,
collapseWhitespace : true
},
chunks: ['main','c']
}),
new htmlWebpackPlugin({
// 指定生成的html文件的名字
filename : 'd.html',
//生成的文件以根目录下的index.html为模板
template : 'index.html',
// 定义html文件中的title
title : '我是d',
// 打包压缩
minify: {
// 删除注释
removeComments : true,
// 删除空格
collapseInlineTagWhitespace : true,
collapseWhitespace : true
},
chunks: ['main','d']
})
]
};
第一步 首先要引用模板handlebars-loader,将 Handlebars 转移为 HTML。先下载handlebars-loader,然后按照 这里说的方式来配置好模板。
- 在module.exports = {}里面加上这一段
module: {
loaders: [
{
test: /\.hbs$/,
loader: 'handlebars-loader'
},
]
}
第二步 在plugins中定义一些需要的信息。
这里初始化了a,b,c,d四个htmlWebpackPlugin插件,他们的作用都是相同的,就是为我们自动生成一个已经插入脚本文件的html文件,初始化四个就会分别生成四个html文件,名字分别为a.html,b.html,c.html,d.html。
我们定义了title的内容,分别为”我是a/b/c/d。
minify属性用于打包压缩,它自带很多属性,具体的设置都可以在这里查询到。最好的方法还是去npm官网看html-webpack-plugin的文档。
chunks:定义我们需要引入的chunk,不需要的就不会被引入。例如:chunks: [‘main’,’a’];我们只需要添加mian和a的chunk。
excludeChunks:剔除我们不需要的chunk,用法同chunks。
第三步 在根目录下的index.html文件中使用<%= %>这样的语法来获取之前在plugins中定义好的信息。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!--获取title的值-->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<!--我是一行注释,看看最后我还在不在-->
<!--获取脚本的src-->
<script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
</body>
</html>
- 之后生成的html文件每一个都会引用main这个chunk和他们在chunks里面定义的chunk。
第四步 npm run webpack 看看生成了什么
分别生成了4个html文件,和a,b,c,d,main五个脚本文件。
看看html文件的内容,如下是a.html:
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>我是a</title></head><body><script src="http://kuma.com/js/main.js"></script><script type="text/javascript" src="http://kuma.com/js/main.js"></script><script type="text/javascript" src="http://kuma.com/js/a.js"></script></body></html>
内容进行了压缩,且给title赋予了之前设定好的值,分别引入了两个脚本文件,后面的b,c,d也是同理,就不一一贴上去了。
==补充== : html-webpack-plugin有一个属性叫inject,如果我们改为false,就不会自动在生成的html文件中插入脚本文件,它的默认值是body,所以其实我们不需要在index.html的文件里对script进行<%= %>的设置,只要在chunks里面定义的所需要的chunk,生成的html文件里会自动添加chunks里面所需要的脚本文件。
- 此时的index.html文件如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!--获取title的值-->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
- 这里拿a.html实例,生成的代码如下,自动添加了所需要的脚本文件a和main。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!--获取title的值-->
<title>我是a</title>
</head>
<body>
<script type="text/javascript" src="http://kuma.com/js/main.js"></script>
<script type="text/javascript" src="http://kuma.com/js/a.js"></script>
</body>
</html>
代码优化
上述生成的脚本文件的src值是一个带http协议的地址,这样的话会拖慢运行的速度,下面提供一个==优化==的办法,通过实现script标签inline的插入。
doctype html
html
head
meta(http-equiv="Content-type" content="text/html; charset=utf-8")
title #{htmlWebpackPlugin.options.title}
body
each cssFile in htmlWebpackPlugin.files.css
style !{compilation.assets[cssFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()}
each jsFile in htmlWebpackPlugin.files.js
script(type="text/javascript") !{compilation.assets[jsFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()}
具体的为什么要这样写我也没完全理解,我来说说我的一些理解。
compilation.assets 我们可以看成是打包编译后的入口文件对象,里面有我们在entry里定义的若干个chunk,都是以键值对的形式存在name : js路径。
因为我们的目标是要过滤掉publicPath里面的内容。
所以可以用:substr(htmlWebpackPlugin.files.publicPath.length)这个方法,通过传入publicPath的长度,从而只取到publicPath内容之后的值。- htmlWebpackPlugin.files.chunks.main.entry就相当于是一个jsFile,可以看成是获取到这个jsFile的key为main的值。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!--获取title的值-->
<title><%= htmlWebpackPlugin.options.title %></title>
<script type="text/javascript">
<%=
htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)
%>
</script>
</head>
<body>
</body>
</html>
- 最后运行一下webpack看一下结果是什么?
<script type="text/javascript">
js/main.js
</script>
可以看到我们在publicPath里面设定的内容都被过滤掉了。
现在按照文档上写的,我们在head里面引入main这个chunk,在body里面引入其他的chunk,遍历除了main以外的chunk。这里只有main这个chunk是以inline的方式引入。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!--获取title的值-->
<title><%= htmlWebpackPlugin.options.title %></title>
<script type="text/javascript">
<%=
compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source()
%>
</script>
</head>
<body>
<% for(var k in htmlWebpackPlugin.files.chunks){ %>
<% if (k !== 'main'){ %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks[k].entry %>"></script>
<% } %>
<% } %>
</body>
</html>
- 此时的webpack.config.js文件,我们只生成一个html文件。里面引入main和abcd五个脚本文件。
// 模块引用
var path = require('path');
var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 入口文件
entry: {
'main' : './src/script/main.js',
'a' : './src/script/a.js',
'b' : './src/script/b.js',
'c' : './src/script/c.js',
'd' : './src/script/d.js'
},
// 出口文件
output: {
path: path.resolve(__dirname,'dist'),
filename: 'js/[name].js',
// 给所有输出文件加上公共的地址头,满足上线要求。
publicPath : 'http://kuma.com/'
},
// 注意: 在path里所有输出的文件目标路径,必须是绝对路径(使用node.js的path模块);
module: {
loaders: [
{
test: /\.hbs$/,
loader: 'handlebars-loader'
},
]
},
// 插件
plugins : [
// 初始化插件,这个插件会为我们自动生成一个已经插入好js脚本文件的html文件。
new htmlWebpackPlugin({
// 指定生成的html文件的名字
filename : 'main.html',
//生成的文件以根目录下的index.html为模板
template : 'index.html',
// 定义html文件中的title
title : '我是main',
// 打包压缩
chunks: ['main','a','b','c','d'],
// 不会自动插入脚本文件
inject : false
})
]
};
- webpack后生成的文件,body里面就是这样,head里面inline的引用太长了,我就不贴出来了。
<body>
<script type="text/javascript" src="http://kuma.com/js/d.js"></script>
<script type="text/javascript" src="http://kuma.com/js/c.js"></script>
<script type="text/javascript" src="http://kuma.com/js/b.js"></script>
<script type="text/javascript" src="http://kuma.com/js/a.js"></script>
</body>