什么是webpack
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
戈德斯文版译文:webpack是一个模块打包器。它的主要目的是将JavaScript文件打包以便在浏览器中使用,并且它也能够转换、打包或构建任何资源或数据。
webpack的宗旨就是把所用用的JavaScript还是css,或者是图片,甚至各类预编译器、js的超集语言,都直接打包成最纯粹的js、css、jpg和png。 在前端工程化,自动化的路上插了好多路灯。
Webpack与Gulp、Grunt区别
Gulp和Grunt的工作方式是在一个配置文件中写好对某一类文件进行某种或几种操作,然后可以自动帮你转换、压缩等一系列操作,在自动化有一定的帮助。
而webpack则是在自动化处理各类文件、资源上以后,会把整个项目当成一个整体,从一个入口文件,把所有依赖到的资源都进行整合处理,打包。使用webpack,能真正体会到JavaScript的发展方向——模块化。提高了开发效率,降低了维护成本。
初始化项目
$ mkdir webpack-demo
$ cd webpack-demo
$ npm init
如没有特殊需求,一路回车就完事了,生成package.json的文件。
安装webpack
$ npm install -g webpack webpack-cli
$ npm install webpack --save-dev
构建项目目录
在项目跟目录下执行
$ mkdir src // 创建源代码目录
$ mkdir public // 创建公共模板目录
$ cd src // 进入源代码目录
$ mkdir components // 创建组件目录
$ touch index.js // 创建项目入口文件
$ touch App.js // 创建App组件
$ cd ../public // 回到项目跟目录,进入公共模板目录
$ touch index.html // 创建公共模板文件
$ cd .. // 返回跟目录
$ mkdir dev // 创建开发目录
$ mkdir dist // 创建生产目录
$ touch webpack.config.dev.js // 创建开发环境webpack配置文件
$ touch webpack.config.prod.js // 创建生产环境webpack配置文件
最后的目录结构
webpack配置
写入最基本的webpack
webpack.config.dev.js
const path = require('path');
module.exports = {
/* 输入配置 */
entry: {
app: './src/index.js' /* 设置项目入口路径 */
},
mode: 'development', /* 配置打包环境为开发环境 */
/* 输出配置 */
output: {
path: path.resolve(__dirname, './dev'), /* 配置输出路径 */
filename: 'bundle.min.js', /* 配置输出名称 */
},
};
为了更方便的在命令行中执行webpack打包命令,我们在package.json写上
{
"scripts": {
"start": "webpack --config webpack.config.dev.js"
}
}
这样在命令行中输入npm run start
就可以执行根据webpack.config.dev.js的webpack打包过程了。
如果想要动态监听文件变化需要在命令后面添加 --watch。
引入react
安装react
$ npm install react react-dom
安装好以后在./src/index.js
写上
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDom.render(, document.getElementById('root'));
然后在./src/App.js
中写
import React from 'react';
import './App.less';
const App = () => (
首页
);
export default App;
因为只是demo,没有写任何方法和生命周期函数,所以写的无状态组件
最后在./public/index.html
写上模板,主要是写一个id为root的div
webpack react
loader
webpack单单自己是不能对各种资源进行处理的,所以要借用各种loader来进行资源处理
css-loader、style-loader和less-loader
我们先来配置处理css文件的loader,直接加上处理预编译器less的loader
首先,安装各种这三个loader,并且安装less,如果你使用的sass或者stylus,可以安装对应的预编译器和loader
$ npm install less less-loader css-loader style-loader --save-dev
安装完以后进行在webpack.config.dev.js
中用上他们
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.(css|less)$/,
use: ['style-loader', 'css-loader', 'less-loader'],
include: path.resolve('./src'),
},
]
}
...
};
这样就不会有问题了,注意!!loader的顺序一定不要搞错,因为loader是按从最后一个往前处理的,先用less-loader处理,最后用style-loader处理。
url-loader
处理静态文件,安装
$ npm install url-loader
配置webpack.config.dev.js
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.(css|less)$/,
use: ['style-loader', 'css-loader', 'less-loader'],
include: path.resolve('./src'),
},
{
test: /\.(png|jpg|jpeg)$/,
use: 'url-loader?limit=8192&name=images/[name].[hash].[ext]',
include: path.resolve('./src'),
},
]
}
...
};
limit:
表示超过多少就使用base64来代替,单位是byte
name:
可以设置图片的路径,名称和是否使用hash
babel,处理react语法和es新语法
babel是什么呢???
这是官方解释,意思是babel是一个javascript的编译器,可以让你在现在用上下一代javascript。众所周知,现在浏览器各自执行的标准并不是很统一,版本不同,支持的javascript的语法也不同,babel就是帮助我们把我们写出来的新兴javascript语法转换成配置的浏览器版本可以识别的语法。具体的可以看Babel官网和Can i use官网
安装babel和babel-loader
$ npm install babel-core babel-loader --save-dev
配置webpack.config.dev.js
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.(css|less)$/,
use: ['style-loader', 'css-loader', 'less-loader'],
include: path.resolve('./src'),
},
{
test: /\.(png|jpg|jpeg)$/,
use: 'url-loader?limit=8192&name=images/[name].[hash].[ext]',
include: path.resolve('./src'),
},
{
test: /\.(js|jsx)$/,
use: [
{
loader: 'babel-loader',
},
],
include: path.resolve('./src'),
},
]
}
...
};
如果这个时候你执行一下npm run start
,会发现报错
提示我们如果用babel-loader@8的话,必须用babel的7版本以上,就是babel-core必须是7以上,我们看一下我们的package.json
看问题就出在这里,所以我们需要重新安装babel-loader,以搭配对应的babel-core
$ npm install babel-loader@7
这样我们就可以执行npm run start
了
目前我还不知道babel的版本有什么区别,可以立个TODO,有空可以具体看一下babel的版本区别
现在我们还需要告诉babel我们用的是什么语法,在根目录创建.babelrc
,其实我们把接下来的配置写在webpack.config.dev.js里也是可以的
$ touch .babelrc
并且在.babelrc
中写入
{
"presets": [
"es2015",
"react"
]
}
并且安装对应的处理插件
$ npm install babel-preset-es2015 babel-preset-react
使用HtmlWebpackPlugin插件
在我们之前打包后的目录下只有一个js文件,而我们需要手动在./public/index.html
中引用才能起作用,现在,HtmlWebpackPlugin就是帮我们把打包后的js和html一起生成。这就是为什么称./public/index.html
为模板的原因。
安装
$ npm install html-webpack-plugin
配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
filename: path.resolve('./dev', 'index.html'),
template: path.resolve('./public', 'index.html'),
})
]
};
现在执行npm run start
以后,./dev
下面就会有一个js文件一个html文件,并且html里面已经引用好了js
使用webpack-dev-server热更新
现在有一种情况就是,每次我们更改完文件,需要手动打包,然后手动刷新页面,就算我们用--watch
,还是会需要手动刷新页面,才能看到我们更改后的样子,现在有了webpack-dev-server,就省去了我们手动刷新页面,并且是基于node在本地起一个服务以便于让我们的代码更真实的从服务器返回的场景,而不是手动双击html文件了。
安装
$ npm install webpack-dev-server --save-dev
更改package.json中的start
命令
{
"scripts": {
"start": "webpack-dev-server --config webpack.config.dev.js"
}
}
更改webapck.config.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
devServer: {
"contentBase": './dev',
"compress": true,
},
};
contentBase:
表示server文件的根目录
compress:
表示开启gzip
webpack-dev-server默认情况下会将output的内容放在内存中,是看不到物理的文件的,如果想看到文件,需要下载另一个插件。
这个时候如果你执行了npm run start
,会看到如下画
从图上我们可以看到,webpack-dev-server帮我们在本地8080端口起了一个服务,并且直接访问
./dev
目录
模块热替换(Hot Module Replacement)
模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,webpack-dev-server虽然手动刷新页面变成了自动刷新,但是!!但是!!模块热替换可以把刷新都省了,页面直接变。
配置
更改webpack.config.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
...
devServer: {
contentBase: './dev',
compress: true,
hot: true,
},
plugins: [
new HtmlWebpackPlugin({
filename: path.resolve('./dev', 'index.html'),
template: path.resolve('./public', 'index.html'),
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
};
安装react-hot-loader
$ npm install react-hot-loader
并在src目录下新建Container.js
import React from 'react';
import { hot } from 'react-hot-loader';
import App from './App';
const Container = () => (
);
export default hot(module)(Container);
更改./src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Container from './Container';
ReactDOM.render(, document.getElementById('root'));
更改webpack.config.dev.js
{
"scripts": {
"start": "webpack --config webpack.config.dev.js"
}
}
执行npm run start
,更改代码保存,会发现页面不会刷新,但是内容会改变,css自带热模块替换,所以现在更改js和css,页面都会自己的更替新的内容
到这,用webpack构建一个react开发环境已经完成
启用eslint
再说一下eslint,没有规矩,不成方圆,国有国法,家有家规。写代码自然也要遵守一定的规范,当然,不遵守规范代码也是可以跑通,但是在后期维护和易读性上,肯定没有按着一定规范写出来的代码好看。所以可以采用用eslint来进行代码规范检查,并且选用airbnb这家公司的规范。
安装
$ npm install -g eslint // 全局安装eslint
$ eslint --init // 在项目跟目录进行eslint初始化,并根据选择,选择airbnb规范
并且在自己的编辑器上配好eslint,该装插件装插件,该改设置改设置
结尾
在这我只是简单的建了一个开发环境,生产环境有时间再出一个,对于各个loader还有很多的options可以设置,webpack还有很多的插件都没有涉及,什么代码分离,tree-shaking都没有讲到,大家可以自己查看webpack的相关文档,真的很有帮助。
加油!