Webpack是什么?
Webpack是当下最热门的前端资源模块化管理和打包工具。
它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码隔离。通过loader的转换,任何形式的资源都可以视作模块,比如CommonJS模块、AMD模块、ES6模块、CSS模块、图片、JSON、Coffeescript、LESS等。
简单的来说,Webpack就是一个模块打包器,它对模块的依赖关系进行静态分析,然后把这些模块按照相应的规则放在不同的文件夹里assets。
Webpack同时支持同步以及异步。
webpack本身只能支持原生的JavaScript模块,但是loader转换器可以将各种资源转换成JS模块。
以前
以前,或者说我们初学代码的时候,基本是一个单页面,然后通过<script>
标签来一个个加载JS文件,但是这种方式的缺点也很明显。
* 全局作用域下容易造成变量冲突
* 文件只能按照<script>
标签的顺序来加载
* 开发人员必须解决模块之间的依赖关系
* 难以维护
现状
前端开发早已不是单纯的网页模式,现在类似于webapp,在现代的高级浏览器里,需要使用HTML5、CSS3以及ES6等更新的技术开发丰富的功能,更像一个单页面应用。
每一个视图通过异步的方式加载,这导致页面初始化以及使用过程中会加载越来越多的JS代码,这给前端开发的流程和资源组织带来巨大的挑战。
模块化的规范
CommonJS
CommonJS规范的核心在于,每个模块通过require方法来同步加载所依赖的其他模块,然后通过exports
或module.exports
来导出需要暴露的接口。
优点:
* 服务器端模块便于重用
* NPM中已经有将近20万个可以使用模块包
* 简单并容易使用
缺点:
* 同步的模块加载方式不适合浏览器
* 不能非阻塞并行加载多个模块
例子:Browserify
AMD
AMD是指Asynchronous Module Definition,只有一个主要接口define(),但是需要提前声明所有需要用到的依赖,简称依赖前置。
优点:
* 可以异步加载
* 可以并行加载
缺点:
* 阅读开发困难
例子: RequireJS,curl
CMD
CMD是指Common Module Definition,与AMD不同的是它是依赖就近,延迟执行,容易在node.js中运行。
例子: Sea.js和coolie
UMD
兼容AMD与CMD的语法糖
ES6模块
ES6的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,输入以及输出量。
例子: Babel
关于前端模块加载
多次加载,请求次数过多;单词打包加载,初始化慢。
分块加载,按需进行懒加载才是未来发展方向。
webpack基础配置纪实
entry 打包入口配置
接受三种方式:string、array、object
module.exports = {
entry: './src/main.js'
...
}
module.exports = {
entry: ['./src/main.js', './src/test.js']
...
}
module.exports = {
entry: {
main: './src/main.js',
test: './src/test.js'
}
...
}
output打包导出配置
module.export = {
entry: {
main: './src/main.js',
a: './src/a.js'
},
output: {
// path是打包后导出的文件路径
path: './dist',
// 打包后的文件名
// [name]对应文件名
// [hash]打包文件hash值
// [chunckhash]打包后每个单独文件的hash值
filename: 'js/[name]-[chunkhash].js',
// publicPath上线环境路径
publicPath: 'http://cdn.com/'
}
...
}
plugins插件系统(数组)
html-webpack-plugin自动化生成项目中的html页面。
通过npm安装
$ npm install html-webpack-plugin --save-dev
在webpack.config.js中
var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main: './src/main.js',
a: './src/a.js',
b: './src/b.js',
c: './src/c.js'
},
output: {
path: './dist',
filename: [name]-[chunckhash].js,
public: 'http:cdn.com/'
},
plugins: [
//创建一个htmlWebpackPlugin对象,并传入值
new htmlWebpackPlugin({
template: 'index.html', //生成html文件的模板文件
filename: 'a.html', //目标文件的名称
inject: false, //插入html文档中的位置,value分别为 true,false,head,body
title: 'this is a.html', // 传入的html的title
excludeChunks: ['b', 'c'] // 引入的除b.js 与c.js以外的js文件
}),
]
}
index.html模板文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- 在webpack中默认识别ejs -->
<!-- title的值为htmlWebpackPlugin传入的值 -->
<title><%= htmlWebpackPlugin.options.title %></title>
<script>
// js的行内引入方法
<%= compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
</script>
</head>
<body>
<!-- 再通过循环遍历除去main.js 外联引入对应的js -->
<% for (var k in htmlWebpackPlugin.files.chunks) { %>
<% if (k != 'main') { %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks[k].entry %>"></script>
<% } %>
<% } %>
</body>
</html>
Loaders
- babel-loader
- css-loader
- style-loader
- postcss-loader
- less-loader
- sass-loader
- html-loader
- ejs-loader
- file-loader
- url-loader
- image-webpack-loader
Loader中所有项目源码均为单页面应用。
Loaders 同样也是一个数组,需要定义在一个module中。
module: {
loaders: [
...
]
}
babel-loader
babel-loader 用于对ES6的代码的转换,首先在终端中执行npm。
npm install --save-dev babel-loader babel-core
然后再webpack.config.js中加入,
module.exports = {
context: '__dirname',
entry: './src/app.js',
output: {
path: './dist',
filename: 'js/[name].bundle.js'
},
module: {
loaders: [{
test: /\.js$/,
loader: 'babel',
include: path.resolve(__dirname, 'src'), //path.resolve node的api,用于处理路径;__dirname为当前项目目录,
exclude: path.resolve(__dirname, 'node_modules'),
query: {
presets: ['latest'] // babel的配置,可在webpack.config.js中配置也可在package.json或创建.babelrc文件
}
}
]
}
}
css-loader & style-loader & postcss-loader
css-loader 用于处理css模块的打包, style-loader 用于将打包好的css模块插入html中,安装。
npm install --save-dev css-loader
npm install --save-dev style-loader
在webpack.config.js中加入
loaders: [
{
test: /\.css$/,
loader: 'style-loader!css-loader' // loader处理顺序是css-loader打包css文件,后通过style-loader插入到html中
}
]
在处理浏览器兼容的情况下,需要对各个浏览器加前缀,这时需要css后处理器postcss-loader,安装
npm install --save-dev postcss-loader
npm install --save-dev autoprefixer // 自动添加前缀
module: {
loaders: [
{
test: /\.css$/,
loader: 'style-loader!css-loader!postcss-loader' // loader处理顺序post-loader处理后加上浏览器的前缀,再由css-loader打包css文件,后通过style-loader插入到html中
}
]
},
postcss: [
require('autoprefixer')({
browsers: ['last 5 versions'] //浏览器的最新五个版本
})
],
如果多个css文件之间存在@import,以上配置还需要修改
module: {
loaders: [
{
test: /\.css$/,
loader: 'style!css?importLoaders=1!postcss' // css-loader的importLoaders参数可以解决@import的css文件不处理的问题
}
]
},
postcss: [
require('autoprefixer')({
browsers: ['last 5 versions'] //浏览器的最新五个版本
})
],