Webpack2.x 笔记
date
Mar 5, 2017
slug
webpack2.x-note
status
Published
tags
Webpack
summary
Webpack2.x 使用总结,包括与gulp、grunt对比以及常用loader配置
type
Post
webpack 2.x 用了小一个月了,一直都是照猫画虎。这俩天开始细读官网的部分文章结合一些讲解视频,深入学习一下。小结一发来汇总知识点。
为什么使用 Webpack
已存在的模块打包器(gulp、grunt)对于大型应用(大型的SPA)来说并不适合。发展另一个模块打包器最迫切的原因那就是代码分割(Code Splitting)、dll,并且可以让静态资源能够无缝的适用于模块化。
Webpack 能做的事情
- 将项目间的依赖分割成代码块并按需加载
- 将初始化载入时间保持在最低
- 每一个静态资源都应被作为一个模块
- 有将第三方的库整合为模块的能力
- 有定制模块的能力
- 适合大型的单页(多页)应用
Webpack 的特点
- 代码分割:webapck 在它的依赖树中有俩种依赖关系,同步与异步!异步依赖可以分割成许多不同的点(部分)并且这些依赖来自于新的代码块。在块级树生效后,一个文件会被传递给每一个代码块。
- 加载器:webpack 是唯一的与生俱来就具有处理 JS 代码的能力,但是加载器被用来将其他源文件转换为 JS 文件。这样来做我们就可以处理来自不同模块的源文件。
- 智能解析:webpack 可以智能解析第三方库文件。它甚至允许在依赖中出现解释性的描述例如:
require("./templates/" + name + ".jade")
。具有 CMD&AMD&es6 三种处理模式。
- 插件系统:webpack 最有特点的就是它生态丰富的插件系统。许多内部的特性都建立在这个插件系统之上。它允许你定制你自己的需求并且可以将其开源。
具体可参考:
Webpack 与 Gulp/Grunt 的区别
Gulp/Grunt 是流程工具,其工作方式是在一个配置文件中,指明对某些文件进行的操作(诸如编译,组合,压缩等任务)的具体步骤,之后可以自动完成这些任务。流程如下:
WebPack则是一个模块打包器,其工作方式通过主文件(index.js)找到全部依赖(自己设置的代码块、第三方库等)使用 loaders 处理,最终打包为可执行的 Javascript 文件。流程如下:
Webpack 简单示例
安装&使用
mkdir webpack-1
cd webpack-1
npm init
npm install -d webpack --save-dev
安装完成后,新建 js&html&css ,文件目录如下:
hello.js 代码如下:
require('./world.js');
require('./style.css');
function hello () {
alert('test!');
}
hello();
style.css 中的代码如下:
html , body{
padding: 0;
margin: 0;
}
body{
background-color: red;
}
在 webpack 能做的事情中我们了解到 webpack 具有识别 js 的能力,那css 呢?答案是不能!那怎么解决呢?利用 loaders 来处理。对于 css 文件我们使用 css-loader&style-loader 先利用 npm 分别安装。之后在当前目录下打开 cmd 键入以下命令:
webpack hello.js hello.bundle.js --module-bind css=style-loader!css-loader --watch
module-bind 命令用于启用 loader 处理主文件,watch 用来监视 hello.js 文件的变化,若变化则自动更新 hello.bundle.js 文件。
在项目中我们如果每次都要敲一长串命令的话很麻烦,我们只需要在 package.json 的 script 中配上 webpack 命令。我得配置如下:
"webpack": "webpack --config webpack.config.js --progress --display-modules --colors --display-reasons"
其中 progress&modules&reasons 分别代表过程百分比 / 各模块 / 打包原因。我们可以将webpack的配置单独放在一个配置文件(webpack.config.js)中会自动读取该文件,如果该文件不存在或者名称不一致则需要通过命令行来运行(不存在的话通过 webpack 命令,名称不一致通过 --config 来指定文件)。
对于 webpack 来说入口与出口肯定是必不可少的,那么在配置文件中我们这样写:
module.exports = {
entry: './src/index.js', // entry: ['./src/index-1.js' , './src/index-2.js'] 多入口
output: { //配置文件输出位置
filename: 'bundle.js',
path: './dist/js'
}
};
还有 entry 传入对象的形式入口:
module.exports = {
entry:{
main1: './src/index1.js',
main2: './src/index2.js'
},
output: { //配置文件输出位置
filename: '[name]-[chunkhash].js', // 这里如果还这样写filename: 'bundle.js'的结果是index2会把index1覆盖,所以我们利用内置的占位符 name & chunkhash 来命名
path: './dist/js'
}
};
这样的话在 index.html中引入的 js 文件名我们不可能每次打包完都要手动修改,这样很麻烦。所以我们需要使用插件来自动帮我们设置。
npm install html-webpack-plugin
安装后修改配置文件为:var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main: './src/scripts/main.js',
mainA: './src/scripts/mainA.js'
},
output: { //配置文件输出位置
filename: '[name]-[chunkhash]-bundle.js' //打包的文件名称*/
path : './dist',
filename: 'js/[name]-[chunkhash].js', //把html与js分开存放
publicPath: 'http://bluespace/' //上线地址的绝对路径,自动替换当前项目中相对路径
},
plugins: [
new htmlWebpackPlugin({
//filename: '[hash].index.html', //名称
template: 'index.html', //以什么为模板,一般以配置文件下的index.html为模板
//inject: 'head' //scripts存放的位置
title: 'webpack is good!',
inject: false,
date: new Date(),
minify: { //压缩html文件,去除空格,去除注释
collapseWhitespace: true,
removeComments: true
}
})
]
};
而 index.html 模板的代码如下(html-webpack-plugin支持ejs写法):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title%></title>
<script src="<%= htmlWebpackPlugin.files.chunks.main.entry%>"></script> <!-- 把脚本分开放 -->
<!-- htmlWebpackPlugin.options.date -->
</head>
<body>
<em><%= htmlWebpackPlugin.options.date%></em>
<script src="<%= htmlWebpackPlugin.files.chunks.mainA.entry%>"></script><!--如果想更加优化的话为了减少一次post请求,这里可以直接把script代码放进来,方法如下:
<script>
<%=
compilation.assets[htmlWebpackPlugin.files.chunks.mainA.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source()%>
</script>-->
</body>
</html>
常见 loader 配置
var htmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
entry: './src/app.js',
output: {
path: './dist',
filename: 'js/[name].bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}],
include: path.resolve(__dirname , './src'),
exclude: path.resolve(__dirname , './node_modules') //尽量使用绝对路径会提高打包速度在configruation里面通过exclude和include来提高打包速度
},
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: { importLoaders: 1 }
},
{
loader: 'postcss-loader',
options: {
plugins: function(){
return [
require('autoprefixer')
];
}
}
}
]
},
{
test: /.\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: function(){
return [
require('autoprefixer') // postcss下的自动补全浏览器前缀的插件
];
}
}
},
'less-loader' //使用less或者sass时不用为@import的less/sass添加importLoaders:1因为自动添加。因为less/sass支持import
]
},
{
test: /\.html$/,
use: 'html-loader' // 将html当做字符串处理,对应innerhtml。坏处是不能使用for等模板语法
},
{
test: /\.ejs$/,
use: 'ejs-loader' // 把html当做模板处理
},
{
test: /\.(png|jpg|gif|svg)$/i, //用包管理工具除了模板外的文件放置相对路径没有问题,但是在模板文件中应该![](${require('../../assets/George.jpg')})
use: [
{
loader: 'url-loader', //url-loader可以设置limit若图片体积小于limit的话则通过url-loader转化为base64代码,若大于则调用file-loader
options: {
name: 'assets/[name]-[hash:5].[ext]',
limit: 4000 //经常需要加载的图片利用http请求较好,因为可以享受到缓存,而base64则需每次读取
}
},
'image-webpack-loader' //压缩图片体积
]
}
]
},
plugins: [
new htmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: 'body'
})
]
};