webpack学习笔记
什么是Webpack?
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
为什么要使用Webpack?
现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,就出现了Webpack这种工具。
开始使用Webpack
安装
①进行全局安装
//全局安装
npm install -g webpack
②在项目目录中初始化
//初始化以生成package.js文件
npm init
③在项目目录中局部安装
// 局部安装Webpack
npm install --save-dev webpack
④在项目目录中新建两个文件夹,app文件夹和public文件夹,app文件夹用来存放原始数据和我们将写的JavaScript模块,public文件夹用来存放之后供浏览器读取的文件(包括使用webpack打包生成的js文件以及一个index.html
文件)。接下来我们再创建三个文件:
-
index.html
--放在public文件夹中; -
Greeter.js
-- 放在app文件夹中; -
main.js
-- 放在app文件夹中;
⑤我们在index.html
文件中写入最基础的html代码,它在这里目的在于引入打包后的js文件。(所引入js文件例如本例中的bundle.js
)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Webpack Sample Project</title>
</head>
<body>
<div id='root'>
</div>
<script src="bundle.js"></script>
</body>
</html>
⑦在Greeter.js
中定义一个返回包含问候信息的html元素的函数,并依据CommonJS规范导出这个函数为一个模块:
// Greeter.js
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = "Hi there and greetings!";
//这是一个DOM元素
return greet;
};
⑧main.js
文件中写入下述代码,用以把Greeter模块返回的节点插入页面。
//main.js
const greeter = require('./Greeter.js');
document.querySelector("#root").appendChild(greeter());
正式使用Webpack
通过配置文件来使用Webpack
定义一个配置文件,这个配置文件其实也是一个简单的JavaScript模块,我们可以把所有的与打包相关的信息放在里面。在项目的根目录下新建一个名为webpack.config.js
的文件,我们在其中写入如下所示的简单配置代码:
module.exports = {
//“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录
entry: __dirname + "/app/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后输出文件的文件名
}
}
有了这个配置之后,再打包文件,只需在终端里运行webpack(非全局安装需使用node_modules/.bin/webpack)命令就可以了,这条命令会自动引用webpack.config.js
文件中的配置选项。
更快捷地执行打包任务
npm
可以引导任务执行,对npm
进行配置后可以在命令行中使用简单的npm start
命令来替代上面略微繁琐的命令。在package.json
中对scripts对象进行相关设置即可,设置方法如下:
{
"name": "webpack-sample-project",
"version": "1.0.0",
"description": "Sample webpack project",
"scripts": {
"start": "webpack" // 修改的是这里,JSON文件不支持注释,引用时请清除
},
"author": "zhang",
"license": "ISC",
"devDependencies": {
"webpack": "3.10.0"
}
}
npm
的start
命令是一个特殊的脚本名称,其特殊性表现在,在命令行中使用npm start
就可以执行其对于的命令,如果对应的此脚本名称不是start
,想要在命令行中运行时,需要这样用npm run {script name}
如npm run build
。
生成source maps(使调试更容易)
对小到中型的项目中,eval-source-map
是一个很好的选项,不过需要注意只应该开发阶段使用它(对于打包后输出的JS文件执行具有性能和安全隐患),我们继续对上文新建的webpack.config.js
,进行如下配置:
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
}
}
使用webpack
构建本地服务器(使得浏览器实时监听代码修改,并自动刷新显示修改后的结果)
在webpack
中进行配置之前需要单独安装本地开发服务器
npm install --save-dev webpack-dev-server
然后修改配置文件webpack.config.js
:
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
},
devServer: {
//端口port要是省略,默认为8080
contentBase: "./public",//本地服务器所加载的页面所在的目录
historyApiFallback: true,//不跳转
inline: true//实时刷新
}
}
在package.json
中的scripts
对象中添加如下命令,用以开启本地服务器:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",
"server": "webpack-dev-server --open"
},
Loaders
Loaders的作用
通过使用不同的loader
,webpack
有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如说分析转换scss
为css
,或者把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React的开发而言,合适的Loaders
可以把React的中用到的JSX
文件转换为JS文件。
配置Loaders
Babel
什么是Babel?
Babel是一个编译JavaScript的平台
为什么要使用Babel?
- 让你能使用最新的JavaScript代码(ES6,ES7...),而不用管新标准是否被当前使用的浏览器完全支持;
- 让你能使用基于JavaScript进行了拓展的语言,比如
React
的JSX
;
Babel的安装与配置
Babel其实是几个模块化的包,其核心功能位于称为babel-core
的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-preset-env
包和解析JSX
的babel-preset-react
包)。
// npm一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
然后在webpack中配置Babel:
module.exports = {
devtool: 'eval-source-map',
//“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录
entry: __dirname + "/app/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后输出文件的文件名
},
devServer:{
contentBase:"./public",
historyApiFallback:true,
inline:true
},
module:{
rules:[
{
//利用正则表达式匹配jsx和js格式文件
test:/(\.jsx|\.js)/,
use:{
loader:"babel-loader",
options:{
preset:[
//使得允许解析ES6和JSX语法
"env", "react"
]
}
},
//不处理此文件夹下的文件
exclude:/node_modules/
}
]
}
};
Babel其实可以完全在webpack.config.js
中进行配置,但是考虑到babel具有非常多的配置选项,在单一的webpack.config.js
文件中进行配置往往使得这个文件显得太复杂,因此一些开发者支持把babel的配置选项放在一个单独的名为 .babelrc
的配置文件中。
module.exports = {
devtool: 'eval-source-map',
//“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录
entry: __dirname + "/app/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后输出文件的文件名
},
devServer:{
contentBase:"./public",
historyApiFallback:true,
inline:true
},
module:{
rules:[
{
test:/(\.jsx|\.js)/,
use:{
loader:"babel-loader"
//将options选项移至.babelrc中
},
exclude:/node_modules/
}
]
}
};
//.babelrc
{
"presets": ["react", "env"]
}
CSS
CSS配置
webpack提供两个工具处理样式表,css-loader
和 style-loader
,二者处理的任务不同,css-loader
使你能够使用类似@import
和 url(...)
的方法实现 require()
的功能,style-loader
将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。
首先进行安装:
//安装
npm install --save-dev style-loader css-loader
接着修改webpack.config.js
中的配置文件:
module.exports = {
devtool: 'eval-source-map',
//“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录
entry: __dirname + "/app/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后输出文件的文件名
},
devServer:{
contentBase:"./public",
historyApiFallback:true,
inline:true
},
module:{
rules:[
{
test:/(\.jsx|\.js)$/,
use:{
loader:"babel-loader"
//将options选项移至.babelrc中
},
exclude:/node_modules/
},
{
test:/\.css$/,
use:[
{
loader:"style-loader"
}, {
loader:"css-loader"
}
]
}
]
}
};
注意:我们这里例子中用到的webpack只有单一的入口,其它的模块需要通过 import
, require
, url
等与入口文件建立其关联。
CSS module
被称为CSS modules
的技术意在把JS的模块化思想带入CSS中来,通过CSS模块,所有的类名,动画名默认都只作用于当前模块。(使CSS拥有局部作用域)
配置:
module.exports = {
...
module:{
rules:[
{
test:/(\.jsx|\.js)$/,
use:{
loader:"babel-loader"
//将options选项移至.babelrc中
},
exclude:/node_modules/
},
{
test:/\.css$/,
use:[
{
loader:"style-loader"
}, {
loader:"css-loader",
options:{
modules:true, //指定启用css modules
localIdentName: '[name]__[local]--[hash:base64:5]' //指定css的类名格式
}
}
]
}
]
}
};
使用:
先将要使用的CSS文件引入,例如:
import styles from './Greeter.css';
然后在需要使用的地方通过以下方式调用:
<div className={styles.root}> //使用cssModule添加类名的方法
CSS预处理器
首先安装postcss-loader
和 autoprefixer
(自动添加前缀的插件)
npm install --save-dev postcss-loader autoprefixer
接下来在webpack.config.js
中添加postcss-loader
:
module.exports = {
...
module:{
rules:[
{
test:/(\.jsx|\.js)$/,
use:{
loader:"babel-loader"
//将options选项移至.babelrc中
},
exclude:/node_modules/
},
{
test:/\.css$/,
use:[
{
loader:"style-loader"
}, {
loader:"css-loader",
options:{
modules:true, //指定启用css modules
localIdentName: '[name]__[local]--[hash:base64:5]' //指定css的类名格式
}
}, {
loader:"postcss-loader"
}
]
}
]
}
};
再之后在根目录新建postcss.config.js
,并添加如下代码之后,重新使用npm start
打包,css将会自动添加前缀。
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
插件(Plugins)
Plugins和Loaders的区别
Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX
,Scss
,Less
..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。
使用插件的方法
要使用某个插件,我们需要通过npm
安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例。(plugins是一个数组)
常用插件
HtmlWebpackPlugin
这个插件的作用是依据一个简单的index.html
模板,生成一个自动引用你打包后的JS文件的新index.html
。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。
首先进行插件的安装:
npm install --save-dev html-webpack-plugin
安装完成之后,如果是依照以上教程流程部署环境的话,那么就得修改原先的项目结构:
- 移除
public
文件夹,利用此插件,index.html
文件会自动生成,此外CSS已经通过前面的操作打包到JS中了。 - 在app目录下,创建一个
index.tmpl.html
文件模板,这个模板包含title
等必须元素,在编译过程中,插件会依据此模板生成最终的html页面(如index.tmpl.html
),会自动添加所依赖的 css, js,favicon等文件。 - 在这之后,需要在
webpack.config.js
中配置添加的插件:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
module:{
rules:[
{
test:/(\.jsx|\.js)$/,
use:{
loader:"babel-loader"
//将options选项移至.babelrc中
},
exclude:/node_modules/
},
{
test:/\.css$/,
use:[
{
loader:"style-loader"
}, {
loader:"css-loader",
options:{
modules:true, //指定启用css modules
localIdentName: '[name]__[local]--[hash:base64:5]' //指定css的类名格式
}
}, {
loader:"postcss-loader"
}
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
//传入相关参数
template:__dirname + "/app/index.tmpl.html"
})
]
};
- 新建一个build文件夹存放最终输出文件(需要修改
webpack.config.js
),然后再次运行npm start
就行了。
这篇文章是我参考学习(copy)别人webpack入门教程的时候写下的,写时对文章内容还有不是很理解的地方,需要之后再次阅读。更加具体的内容请参考教程原文:zhangwang的webpack入门教程。