一、webpack 是什么?
webpack 是基于 Node.js 静态资源的模块打包器。当用 webpack 打包时,它会从一个起点开始查找各个模块依赖关系,并且按照这些依赖关系把这些文件打成一个或者多个包;
二、为什么使用webpack?
- 模块化,浏览器端的早期没有模块化,需要 js 文件只能通过 script 标签手动控制依赖管理这些 js 文件的引入顺序;而 webpack 可以通过模块化管理这些依赖;
 - 自动编译 less、sass
 - 可以把基于 JS 的扩展语言编译成 JS;
 - 开发时配置代理解决开发环境跨域
 
三、安装webpack
全局安装 webpack 和 webpack-cli
- 安装 webpack-cli
 
npm install webpack-cli -g
- 安装 webpack
 
npm install webpack -g
四、示例
- 新建文件夹 webpack-sample
 - 在 webpack-sample 下新建文件夹 app、public
 - 在 app 目录下新建 Greeter.js、main.js、config.json
 - 在 public 目录下新建 index.html
 - 写入代码
 
- Greeter.js
 
let config = require('./config.json');module.exports = function () {var greet = document.createElement('div');greet.textContent = config.greetText;return greet;};
- config.json
 
{"greetText":"Hi there and greetings from JSON!"}
- main.js
 
const greeter = require('./Greeter.js');document.querySelector('#root').appendChild(greeter());console.log(12334)
- /public/index.html
 
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div id="root"></div><p class="paragraph">12333</p><div>xxxxxx</div><script src="bundle.js"></script></body></html>
- 在 webpack-sample 目录下打开命令行,输入以下打包命令
 
webpack-cli --entry ./app/main.js --output ./public/bundle.js
- 运行 index.html 页面,可以看到已经成功;
 
五、配置npm scripts
- 前面我们通过命令行打包,需要配置一大堆参数。为了减少这种情况,我们需要配置 npm scripts
 
npm scripts 配置
- 首先生成一个 package.json 文件
 - 在 package.json 中有一个 scripts 对象,在这个对象中的每一个属性都是一个可以通过 npm run 执行的命令;
 - 以上面打包示例
 
{"name": "wbp","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","cmdBuild": "webpack-cli --entry ./app/main.js --output ./public/bundle.js"},"keywords": [],"author": "","license": "ISC"}
- 然后在 cmd 中执行 npm run cmdBuild 就相当于在执行 webpack-cli —entry ./app/main.js —output ./public/bundle.js 命令;
 
六、webpack 配置文件
- webpack 是基于 Node.js 的,在项目根目录下创建一个 webpack.config.js,webpack 打包时会自动加载文件名为 webpack.config.js 的文件;
 - 我们的配置文件要导出一个配置对象;
 
6.0 本地安装 webpack-cli、webpack
npm install webpack-cli webpack --save-dev
6.1 配置entry、output
- entry(入口)是 webpack 打包的起点,它从这个文件开始查找各个模块之间的依赖
 - output(出口)是 webpack 打包后的文件输出目录和文件名;
 
示例:
module.exports = {entry: __dirname + '/app/main.js',output: {path: __dirname + '/public', // 打包后文件存放的地方filename: 'bundle.js'}};
6.2 配置 source-map
什么是 source-map?
js 代码编译后变得可读性非常差,不利于调试;而浏览器有一种 source-map 机制,可以通过 source-map 把代码虚拟还原成打包之前的样子,这样方便调试;
webpack在打包结束后可以自动生成 source map
- 在配置中加入 devtool 属性
 
module.exports = {devtool: "eval-source-map", // 生成source-mapentry: __dirname + '/app/main.js',output: {path: __dirname + '/public', // 打包后文件存放的地方filename: 'bundle-[hash:5].js'}};
6.3 配置打包的 npm scripts
- 在 package.json 中配置 build 命令;
 
{"name": "wbp","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack","cmdBuild": "webpack-cli --entry ./app/main.js --output ./public/bundle.js"},"keywords": [],"author": "","license": "ISC"}
- 在命令行中执行 npm run build 即可打包
 
6.4 配置 dev-server
在开发的过程中我们可以让 webpack 给我们启动一个本地服务器,它可以:
- 让浏览器监听你的代码的修改,并自动刷新显示修改后的结果;
 - 提供 AJAX 接口的代理,解决开发环境的跨域问题
 
- 安装 webpack-dev-server
 
npm install --save-dev webpack-dev-server
- 在 webpack 配置中加入配置项
 
module.exports = {devtool: "eval-source-map", // 生成 source-mapentry: __dirname + '/app/main.js',output: {path: __dirname + '/public', // 打包后文件存放的地方filename: 'bundle1.js'},devServer: {contentBase: './public', // 本地服务器所加载的页面所在的目录historyApiFallback: true, // 单页面应用路由切换时不跳转inline: true, // 实时刷新port: 8080,proxy: {'/api': { // 如果接口中带有 API 标志,那么就需要开始代理target: 'http://localhost:8001',changeOrigin: true, // target 是域名的话,需要这个参数,secure: false // 设置支持 https 协议的代理,不检查安全与否}}}};
- 配置详解
- contentBase: ‘./public’, 本地服务器所加载的页面所在的目录
 - historyApiFallback: true, 单页面应用路由切换时不跳转
 - inline: true, // 实时刷新
 - port: 8080, 启动时的端口号
 - proxy: 代理配置
 
 
- 配置 npm scripts,启动 webpack 的 dev-server:
 
{"name": "wbp","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack","cmdBuild": "webpack-cli --entry ./app/main.js --output ./public/bundle.js","dev": "webpack-dev-server --open"},"keywords": [],"author": "","license": "ISC","devDependencies": {"webpack-dev-server": "^3.7.2"}}
七、配置loaders
webpack 中一切皆模块,js、css、图片等。但是原则上,webpack 只能处理 js 文件。此时就需要借助 loader 的力量;
7.1 loader 是什么?
原则上,webpack 只能处理 js 文件,但是通过使用不同的 loader,webpack 有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如说分析转换 less 为 css,或者把下一代的 JS 文件(ES6,ES7)转换为现代浏览器兼容的 JS 文件,对 React 的开发而言,合适的 Loaders 可以把 React 中用到的 JSX 文件转换为 JS 文件。
Loaders 需要单独安装并且需要在 webpack.config.js 中的 modules 关键字下进行配置,Loaders 的配置包括以下几方面:
- test:一个用以匹配 loaders 所处理文件的拓展名的正则表达式(必须)
 - use:loader 的名称(必须)
 - include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
 - query:为 loaders 提供额外的设置选项(可选)
 
7.2 配置Babel
Babel 其实是一个编译 JavaScript 的平台,让你能使用最新的 JavaScript 代码(ES6,ES7…),而不用管新标准是否被当前使用的浏览器完全支持;让你能使用基于 JavaScript 进行了拓展的语言,比如 React 的 JSX;
- 安装Babel,需要安装
- babel-core babel 的核心
 - babel-loader babel的 loader (安装7.x.x 版本,如7.1.5)
 - babel-preset-env 把 ES5/6/7 转成当前能使用的版本
 - babel-preset-react 解析 React 的 JSX 语法
 
 
/ npm一次性安装多个依赖模块,模块之间用空格隔开npm install babel-core babel-loader@7.1.5 babel-preset-env babel-preset-react --save-dev
- 在 webpack 配置文件中加入 loader 信息;
 
- 在webpack 加入 module 配置
 
module.exports = {devtool: "eval-source-map", // 生成 source-mapentry: __dirname + '/app/main.js',output: {path: __dirname + '/build', // 打包后文件存放的地方filename: 'bundle1.js'},devServer: {contentBase: './public', // 本地服务器所加载的页面所在的目录historyApiFallback: true, // 单页面应用路由切换时不跳转inline: true, // 实时刷新port: 8080,proxy: {'/api': { // 如果接口中带有 API 标志,那么就需要开始代理target: 'http://localhost:8001',changeOrigin: true, // target 是域名的话,需要这个参数,secure: false // 设置支持 https 协议的代理,不检查安全与否}}},module: {rules: [{test: /(\.jsx|\.js)$/,use: {loader: "babel-loader",options: {presets: ['env', 'react']}},exclude: /node_modules/}]}};
7.3 配置CSS loader
CSS 也可以像 js 一样的导入进来;
- 安装 css-loader 和 style-loader;
- 安装 css-loader 可以使用 @import 或者 url 等方法导入其他资源
 - style-loader 将所有计算后的样式加入页面中
 
 
npm install --save-dev style-loader css-loader
- 在 webpack 中配置 css-loader
 
module.exports = {devtool: "eval-source-map", // 生成 source-mapentry: __dirname + '/app/main.js',output: {path: __dirname + '/public', // 打包后文件存放的地方filename: 'bundle.js'},devServer: {contentBase: './public', // 本地服务器所加载的页面所在的目录historyApiFallback: true, // 单页面应用路由切换时不跳转inline: true, // 实时刷新port: 8080,proxy: {'/api': { // 如果接口中带有 API 标志,那么就需要开始代理target: 'http://localhost:8001',changeOrigin: true, // target 是域名的话,需要这个参数,secure: false // 设置支持 https 协议的代理,不检查安全与否}}},module: {rules: [{test: /(\.jsx|\.js)$/,use: {loader: "babel-loader",options: {presets: ['env', 'react']}},exclude: /node_modules/},{test: /\.css$/,use: [{loader: 'style-loader'},{loader: 'css-loader'}]}]}};
- 写一个css文件
 
- main.css
 
* {margin: 0;padding: 0;}div {font-size: 30px;color: red;}
- 在main.js 中导入css
 
import './main.css';
7.4 配置less
配置 less-loader 以后,我们写 less webpack 会帮我们编译成 css,就不需要我们再引入 js 文件;
- 安装less、less-loader
 
npm install less less-loader --save-dev
2 配置 less-loader
module.exports = {devtool: "eval-source-map", // 生成 source-mapentry: __dirname + '/app/main.js',output: {path: __dirname + '/build', // 打包后文件存放的地方filename: 'bundle.js'},devServer: {contentBase: './public', // 本地服务器所加载的页面所在的目录historyApiFallback: true, // 单页面应用路由切换时不跳转inline: true, // 实时刷新port: 8080,proxy: {'/api': { // 如果接口中带有 API 标志,那么就需要开始代理target: 'http://localhost:8001',changeOrigin: true, // target 是域名的话,需要这个参数,secure: false // 设置支持 https 协议的代理,不检查安全与否}}},module: {rules: [{test: /(\.jsx|\.js)$/,use: {loader: "babel-loader",options: {presets: ['env', 'react']}},exclude: /node_modules/},{test: /\.css$/,use: [{loader: 'style-loader'},{loader: 'css-loader'}]},{test: /\.less$/,use: ['style-loader', 'css-loader', 'less-loader']}]}};
7.5 配置 url-loader
配置 url-loader 后,我们可以导入图片;
- 安装 url-loader
 
npm install url-loader --save-dev
- 配置 url-loader
 
module.exports = {devtool: 'eval-source-map',entry: __dirname + '/app/main.js',output: {path: __dirname + '/public',filename: 'bundle.js'},devServer: {contentBase: __dirname + '/public',historyApiFallback: true, // 单页面应用路由切换时不请求服务器inline: true, // 实时刷新port: 8080,proxy: {'/api': { // 如果接口中带有 api,就代理转发到 targettarget: 'http://localhost:8001',changeOrigin: true, // 如果 target 是域名的话,需要整个参数secure: false // 不校验安全,允许访问 https}}},module: {rules: [{test: /\.(js|jsx)$/,use: {loader: 'babel-loader',options: {presets: ['env', 'react']}},exclude: /node_modules/},{test: /\.css$/,use: [ 'style-loader', 'css-loader']},{test: /\.less$/,use: ['style-loader', 'css-loader', 'less-loader']},{test: /\.(png|jpg|gif)$/,use: {loader: 'url-loader'}}]}};
八、插件
插件(Plugins)是用来拓展 Webpack 功能的,它们会在整个构建过程中生效,执行相关的任务。Webpack 有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。
使用插件
要使用某个插件,我们需要通过 npm 安装它,然后要做的就是在 webpack 配置中的 plugins 关键字部分添加该插件的一个实例;
- 让 webpack 打包后帮我们引入打包后的js文件;
 
实现以上功能需要一个插件;html-webpack-plugin,首先安装它;
- 安装
 
npm install html-webpack-plugin --save-dev
- 引入插件
 
let HtmlWebpackPlugin = require('html-webpack-plugin');
- 在 webpack 中增加一个 plugins 字段,它的值是一个数组,使用插件就是创建一个插件的实例,然后作为数组项放到 plugins 中;
 
let HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {devtool: "eval-source-map", // 生成 source-mapentry: __dirname + '/app/main.js',output: {path: __dirname + '/build', // 打包后文件存放的地方filename: 'bundle.js'},devServer: {contentBase: './public', // 本地服务器所加载的页面所在的目录historyApiFallback: true, // 单页面应用路由切换时不跳转inline: true, // 实时刷新port: 8080,proxy: {'/api': { // 如果接口中带有 API 标志,那么就需要开始代理target: 'http://localhost:8001',changeOrigin: true, // target 是域名的话,需要这个参数,secure: false // 设置支持 https 协议的代理,不检查安全与否}}},module: {rules: [{test: /(\.jsx|\.js)$/,use: {loader: "babel-loader",options: {presets: ['env', 'react']}},exclude: /node_modules/},{test: /\.css$/,use: [{loader: 'style-loader'},{loader: 'css-loader'}]},{test: /\.less$/,use: ['style-loader', 'css-loader', 'less-loader']},{test: /\.(png|jpg|gif)$/,use: 'url-loader'}]},plugins: [new HtmlWebpackPlugin({template: __dirname + '/public/index.html' // 指定一个模板,webpack 将会按照这个模板创建 html})]};
- 做完这些后,我们修改输出路径为 build;
 - 执行 npm run build
 
执行后我们发现在 build 目录下有一个 index.html 和 bundle.js;同时 index.html 已经自动引入了 bundle.js
【发上等愿,结中等缘,享下等福,择高处立,寻平处住,向宽处行】
