本文是在windows系统下使用webpack,其他系统只有命令行工具使用方式有区别,您可放心食用。
1 什么是webpack
webpack是一个前端开发打包工具。
它打包的是什么
通下面这张图片可以看出,webpack可以将我们开发项目时编写的多个不同类型的模块依赖文件(其实就是我们写的各个代码文件),打包成为几个静态资源文件(用来在浏览器上运行)
为什么要使用webpack
如果你现在只是在简单地学习html/css/js,那么你就不会体会到webpack对你是否有用,如果你已经具备了一些前端基础,准备做一个完整项目练练手,那么使用webpack吧,他就像你的总管,帮你自动处理各种你本来需要亲自动手的事情,比如es6转换为es5(现在大多浏览器对还不能es6很好的支持,所以要借用babel相关工具进行转换我们编写的es6代码)。
让我们开启webpack之旅吧
安装webpack
推荐使用npm安装webpack
npm是node.js的一个包管理工具,需要先安装node.js才能使用(安装教程请自行百度)。安装完node.js后,新建一个文件夹project,我们的项目就在该文件夹下面建立,project文件夹就是我们项目的根目录。
在项目根目录新建模板文件index.html(模板文件是开始学前端的时候写的那个html文件,只不过这里有更丰富的意义,这是后话,暂且不表)
在安装webpack之前,我们先在项目根目录下面新建一个package.json文件配合webpack使用,这是一个npm安装包的说明文件。我们使用命令行工具cmd,进入我们的项目根目录,自动创建package.json文件.
npm init
一路回车下去,知道最后输入y确认即可。
接下来我们安装webpack,还是在项目根目录下
npm install webpack -g 或者
npm install webpack --save 或者
npm install webpack --save-dev
-g 表示全局安装
--save 和 --save-dev 表示安装到你的项目根目录,--save 会把依赖包名称添加到 package.json 文件的 dependencies 下,--save-dev 则添加到 package.json 文件的 devDependencies 下。dependencies是运行时依赖,devDependencies是开发时的依赖。运行时需要用到的包使用--save,否则使用--save-dev,如果你还是不知道使用哪个,使用--save即可,以后安装的包同理。
配置webpack
在package.json中对scripts对象进行相关设置
"scripts": {
"start": "webpack" // 修改的是这里,使用npm start 启动打包命令,直接用webpack命令也是一样的
},
如果想要在运行webpack的时候,使用一些webpack的参数,可以在package.json 文件中配置
"scripts":{"webpack": "webpack --config webpack.config.js --progress看到打包过程 --display-modules看到打包了哪些模块" --color彩色字体 --display-reason打看到包原因}
在项目根目录下面创建webpack配置文件webpack.config.js
//基本结构
module.exports = {
var path = require('path');
context: path.join(__dirname), //这是entry配置项的根目录(绝对路径)
entry: "./src/root.js",//打包入口文件,就是打包谁
output: {
path: __dirname + "/dist/",//打包后文件放置的目录路径
// publicPath: "发布项目时在相对路径前面添加的绝对路径"
filename: "bundle.js"//打包后文件的名字
}
}
context是运行webpack打包程序时的上下文环境(项目根目录),__dirname(注意是两个下划线)是node.js的一个全局环境变量。
entry:
写法一:字符串 ----------打包一个入口文件,如上
写法二: 数组 ------------['./a.js', './b.js'] 打包两个不相依赖的文件,打包在一起
写法三:对象----------在多页面应用中,针对不同的页面填写不同的入口文件
entry: {
page1: './a.js',-----可以是一个
page2: ['./as.js', './b.js']-------可以是多个
}
此时如果还像上面那样子写output则只会生成一个输出文件,且后面的打包文件会把前面输出文件覆盖,解决方法是在filename中添加一个占位符,区分不同输出文件,方法有三种:
1 [name] 就是entry对象的key值,page1, page2
output: {
filename: '[name]'.js,
path: __dirname + 'src'
}
2 [hash] 每次打包生成的一个hash值,假设为“123asd”,可以和[name]一起使用
output: {
filename: '[name]-[hash]'.js,
path: __dirname + 'src'
}
多个打包生成文件hash相同,都是“123asd”
3 [chunkhash] 每一个chunk自己的hash值----打包时可以看到chunk(模块),多个打包生成文件hash不同,可以和其他两个结合使用。
那么问题来了,因为我们使用了hash值来编码打包后生成的文件,而我们的html文件引用这个js文件时就必须保持同名,所以每次打包都需要手动更改引用文件的名字,相当麻烦。
我们可以使用一个插件来自动帮助我们引用打包后的js文件。
webpack插件 html-webpack-plugin
官网:https://www.npmjs.com/package/html-webpack-plugin
先利用npm安装
npm install html-webpack-plugin --save-dev
然后在webpack.config.js文件中引用
const htmlWebpackPlugin = require('html-webpack-plugin');
在 export.modules = {}中填写
plugins: [
new htmlWebpackPlugin({----------初始化插件
template: 'index.html'-------模板文件(插件作用下生成文件的模板),注意这个路径就是当下目录,因为webpack中有一个运行上下文(context),即webpack的运行所在目录,而index.html在当下目录,所以路径这样写没问题
})
]
新生成的这个index.hml的所在目录也是output的路径下的目录
output: {
filename: 'js/[name]'.js,
path: __dirname + '/dist/'
}
一个index.htm文件会生成在dist目录下,里面有对[name]'.js的引用,[name]'.js会生成在./dist/js/目录下
还可以增加另外一些参数
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'index-[hash].html', //也可以指定生成的文件的名字,
inject: 'head' //指定打包生成的js是在head标签中引用,不强制要求,用false
minify: {---------对项目进行压缩操作
removeComments: true,--------删除注释
collapseWhitespace: true----------删除空格
}
})
]
此时我们根目录下的index.html就不需要填写打包出来的js的引用了
如果有多个页面,同样可以使用这个插件做到,只需要在plugins:[]数组中新增加一向即可,同时利用chunks:[ 'entry的key值' ]参数决定这个文件时要引入哪个入口文件的打包:
entry: {
main: './src/main.js',
a: './src/main.js',
b: './src/main.js',
c: './src/main.js'
}
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'a.html',
inject: 'body' ,
chunks: ['main', 'a']
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'b.html',
inject: 'body' ,
chunks: [ 'b'] 或者 excludeChunks: ['main', 'a', 'c']表示加载排除哪些chunk之外的chunk
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'c.html',
inject: 'body' ,
chunks: [ 'c']
}),
]
到现在webpack的基本配置也就完成了,当然,如果你的项目没有那么复杂,只是用来练手,可以忽略htmlWebpackPlugin这个插件,一样可以完美的使用webpack.
webpack应用之loaders
你会发现,仅仅只有前面的工作,webpack好像并没有多少卵用,反而增加了很多开发工作,想要解开这个困惑,请耐心看下去。
我们说过,webpack是一个管家,既然如此,我们就开始给它安排任务了,正是这些任务的下放,才让我们开发工作如释重负。
什么是loaders
先看官网的定义:
Loaders allow you to preprocess files as you require() or “load” them. Loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle frontend build steps. Loaders can transform files from a different language like, CoffeeScript to JavaScript, or inline images as data URLs. Loaders even allow you to do things like require() css files right in your JavaScript!
大体意思就是,loaders能够帮我们做一些预处理,将不同语言编写的文件处理成能正常使用的样子。
不同的loader具有不用的功能,都需要先安装,推荐使用npm安装。
我们先在这里将两个重要的loader的使用,以起到提纲挈领的作用,更多loader使用将在以后更新。
利用webpack构建本地服务器
webpack-dev-server
在项目根目录安装,就是在cmd命令下利用cd命令,进入我们创建的project文件夹
npm install --save-dev webpack-dev-server
配置
在webpack.config.js的module.exports = {}里面添加下面一项
devServer: {
contentBase: "./",//本地服务器所加载的页面所在的目录,即当前project目录
historyApiFallback: true,//不跳转
inline: true//实时刷新
},
在package.json中配置
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",
"server": "webpack-dev-server --inline --content-base --open"
},
实现修改代码时,页面时时更新。
启动本地服务器,默认是8080端口,cmd进入project文件夹下,运行以下命令
npm run server
注意: 进入项目的根目录运行npm run server,webpack配置文件中本地服务器所加载的页面所在的目contentBase的值应该是从这里开始,比如要加载的文件在项目根目录,那么contentBase: "./"
修改源代码,页面不能实时更新的问题
我们修改我们的源文件后,自动打包生成的bundle.js其实只是一个虚拟的文件,本地其实是没有打包编译的,所以我们不能使用本地路径去引用,在引用打包生成文件bundle.js的时候,将路径改为绝对地址
src="http://localhost:8080/dist/bundle.js",即可
如果你还是没有解决这个问题,打开你的webpack配置文件webpack.config.js,
将publicPath添加进文件输出
output: {
path: __dirname + "/dist/",
publicPath: "/dist/",
filename: "bundle.js"
},
如果问题还没解决,看一下你的webstorm编辑器的设置,参考
https://www.cnblogs.com/wshiqtb/p/5924172.html
补充
npm run server表示运行package.json中"scripts"中的server命令
package.json文件中output的路径:
path----表示你打包后生成的打包文件放在你的电脑的那个目录下
publicPath----表示服务器引用资源的路径(相对于服务器根目录)
webapck对图片的处理
url-loader 或者 file-loader
npm安装方法和前面一样,安装哪一个可以看了下面的介绍自行决定
在模板文件和css文件中引用图片写相对地址,在react组件中引用图片用相对地址找不到图片,可以用绝对地址,从根目录往下写路径,也可以用node的方法
<img src="${ require('相对路径') }">
在webpack.config.js的module.exports = {}里面添加下面一项
{
test: /\.(png|jpg|gif|svg)$/i,
loader: 'file-loader',
query: {
name: 'assets/[name]-[hash:5].[ext]'//打包后的图片放在assets文件夹下,图片名字为 他的,名字+一个5位的hash值,后缀名为ext
}
}
webpack2貌似不支持query,可以直接用loader: 'url-loader?limit=8192&name=img/[name]-[hash].[ext]'这种写法。
另一个处理图片的loader
loader: 'url-loader?limit=8192'
当文件大于limit值(bytes)的时候交给file-loader处理,当文件小于这个值时候,图片被转换成一串base64的编码,直接插入引用图片的文件,使之变大,但是却不用通过http请求单独去请求这张图片资源
有一个loader可以用于压缩图片: image-webpack-------不要忘了先安装
如果和url-loader写在一起,可以这样写:
test: /.(png|jpg|gif|svg)$/i,
loaders: [
'url-loader?limit=8192&name=assets/[name]-[hash:5].[ext]',
'image-loader'
]----------注意loader中如果有多个参数时,处理顺序是从右向左
上面就是两个比较容易出错的loader的使用,更多loader的使用,请参考“入门Webpack,看这篇就够了http://www.jianshu.com/p/42e11515c10f”