webpack学习
第一次接触webpack是学react的时候,然而被吓跑了,完全理解不了啊。之后学vue,把官方配置文件看了下,vue相关的配置大概了解了,也写了一篇文章。最近看vue-ssr,又被webpack搞懵逼了,下定决心跟着文档走了一遍。本文主要还是以配置文件字段介绍为主,毕竟用的最多还是这些。关于安装什么的就不再介绍了。
1.首先配置文件四大块
1.1入口
入口呢是webpack开始检测文件的起点,用过vue的一般都只有一个入口,main.js,当然这么强悍的工具怎么可能只有这么点功能。你也可以使用多入口。
//单入口
entry:"./main.js"
//多入口数组方式
entry:['main.js'...]
//多入口对象方式
entry:{
main:'./main.js'
}
多入口两种写法,但是数组方式不利于扩展,推荐使用对象方式。
1.2输出
输出这里就可以配置一堆东西了,一个一个来。
//输出文件的名字 可以自定义名字,也可以使用入口文件的名字只需要写成[name].js即可,你还可以添加hash:[name].[hash].js
filename:'bundle.js'
//路径,就是你打包之后的文件放到哪里,这里放到dist目录中,注意,这里没有dist目录是会自动创建的
path:path.resolve(__dirname, 'dist')
//设置公共目录
publicPath:'/dist/'
chunkFilename着重介绍下
首先它在config中可以这么写
//id:表示一个序号,hash不必说,chunkhash:n,这里n可以自己配置,生成n位的hash,name就是文件名,具体下面介绍
chunkFileName:[id].[hash].[chunkhash:3].[name].js
这个会单独输出一个包,并不会跟filename中的内容打包到一起,比如有些文件你并不想打包到主文件中,或者减轻首页负担,只在引入的时候才加载。
这个时候你只需要在引入文件的时候使用require.ensure来引入你需要的模块,然后config中配置上面的信息就可以了。
require.ensure(['./add'], function(require){
add = require('./add');
},'name');//这里这个name就会跟上面的[name]同步,不写的话就按照序号来了。
关于library和libraryTarget我也没搞清,就不坑人了。
sourceMapFilename
当你使用sourceMap的时候你可以配置你的输出文件名,就是这个参数
sourceMapFilename:'[file].[id].[hash].map'
1.3module
module中主要是各种loader的配置(loader是对不同文件处理的东西)
module:{
//这里是个数组
rules:[
{
//test是匹配文件的正则表达式
test:/\.js$/,
//使用loader两种方式,loader或者use
loader:'babel-loader',
// use:'babel-loader'
//这里是做一些额外的配置,比如转es2015
//options和query是use:[{options}]的代替
query: {
presets: ['es2015']
}
}
1.4plugin
webpack还支持各种插件,来扩展功能,当然你也可以自己写插件,webpack本身自带有一些插件,比如丑化代码。其他的你只需要安装,并new一个实例即可,这个是个数组
plugins:[
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
})
]
2.其他重要配置项
2.1devtool
这个很简单,比如你在打包的时候,压缩了代码但为了调试你可以输出sourceMap
dev:'sourceMap'
2.2resolve
这个主要是alias选项,作为优化打包性能,在vue的官方配置中你一定见过下面这个
resolve:{
alias:{
'vue$': 'vue/dist/vue.js'
}
}
这里你可以指定引入文件的别名(vue$)以及具体路径,这样webpack就不用在目录中一层一层的查找。
在resolve中你还可以配置下面两项
aliasFields:['browser'],//默认解析规范
extensions:['.js','.json','.css'],//自动解析确定的扩展
2.3externals
这个主要是防止某些包打入bundle中
3.关于开发
在开发中我们都对其提供的热更新最为感兴趣,我们只需要安装webpack-dev-server,然后我们就可以在config中配置了,也就是devServer,直接看代码了
devServer:{
clientLogLevel:"none",
//提供的内容路径
// contentBase:path.join(__dirname, "dist"),
//是否启用gzip压缩
compress:true,
//port 在命令行中,端口号,实际在非命令行中也可以使用
port:9000,
//output.filename设置bundle.js,惰性模式,每个请求结果都会产生全新的编译,使用filename可以只为某个文件被请求时编译
//webpack不会监听任何文件改动,只有请求的时候才编译,watchOptions无效,内联模式应该禁用。
/*lazy: true,
filename: "bundle.js",*/
//请求添加首部内容
headers:{
'X-Custom-Foo':'bar'
},
//任意的404页面可以使用index.html来替换,所以可以直接用localhost:port/index.html来,此时dist目录是个虚拟目录并不会真实的的创建出来,只有webpack命令才会,也就是在build的时候
historyApiFallback: true,
//只用在命令行,指定host,如果希望在外部服务器访问,指定host:"0.0.0.0"
host:"",
//启用热替换
// hot:true,
// hotOnly:true,
//使用https
https:true,
/*https的配置
* https:{
* key:fs.readFileSync(),
* cert:fs.readFileSync(),
* ca:fs.readFileSync(
* }
* */
//两种模式,默认内联模式(inline),处理时重载的脚本会插入到你的包(bundle)中,并且构建消息会出现到浏览器控制台
//iframe inline:false 只在命令行中使用--inline
//noInfo启用 noInfo 后,诸如「启动时和每次保存之后,那些显示的 webpack 包(bundle)信息」的消息将被隐藏。错误和警告仍然会显示。
noInfo:false,
//如果你有单独的后端开发服务器 API,并且希望在同域名下发送 API 请求 ,那么代理某些 URL 会很有用。
// proxy:{
// '/api':"http://localhost:3000"
// },
//请求/api/user会代理到http://localhost:3000/api/user
//如果你不想始终传递 /api ,则需要重写路径:
/*proxy: {
"/api": {
target: "http://localhost:3000",
pathRewrite: {"^/api" : ""}
}
}*/
//命令行使用,内联模式连接指定服务器。
// public:{
//
// },
//启动后除了启动信息都不会显示
/*
* quit:true,
* */
//可以接受一个app对象(express)处理一些请求
// setup(app){
// app.get('/some/path', function(req, res) {
// res.json({ custom: 'response' });
// });
// },
}
4node中使用
我们不止可以在命令行中使用,也可以在node中使用,只需要把webpack和配置文件引入即可
var webpack = require('webpack');
var config = require('./webpack.config');
//这里会返回一个compiler对象
let compiler = webpack(config);
使用插件
compiler.apply(new webpack.ProgressPlugin());
compiler对象主要提供两个方法,run和watch
compiler.run(function(err, stats) {
console.log(stats);
if(err||stats.hasErrors()){
//编译错误不在err中
}
});
watch有两个参数,第一个是配置对象watchOptions,第二个是回调函数handler
watchOptions{
aggregateTimeout:300,//延迟重新构建时间
poll:1000,//轮询间隔(多久检测一次)
ignored:/node_modules/, //也可以使用anymatch方式 "files\/**\/*.js",可以忽略检测某些文件
}
compile.watch()会返回一个watching对象,暴露close(callback)方法,用来结束监听。
我们还可以将编译到内存中,如下
//编译到内存中
const MemoryFS = require("memory-fs");
const webpack = require("webpack");
const fs = new MemoryFS();
const compiler = webpack({ /* options*/ });
compiler.outputFileSystem = fs;
compiler.run((err, stats) => {
// 之后读取输出:
const content = fs.readFileSync("...");
});
其实还是有诸多不理解之处,但是对于我们基本的使用,以及看别人的配置还是有一定帮助的。