一、webpack 是什么?

webpack 是基于 Node.js 静态资源的模块打包器。当用 webpack 打包时,它会从一个起点开始查找各个模块依赖关系,并且按照这些依赖关系把这些文件打成一个或者多个包;

二、为什么使用webpack?

  1. 模块化,浏览器端的早期没有模块化,需要 js 文件只能通过 script 标签手动控制依赖管理这些 js 文件的引入顺序;而 webpack 可以通过模块化管理这些依赖;
  2. 自动编译 less、sass
  3. 可以把基于 JS 的扩展语言编译成 JS;
  4. 开发时配置代理解决开发环境跨域

三、安装webpack

全局安装 webpack 和 webpack-cli

  1. 安装 webpack-cli
  1. npm install webpack-cli -g
  1. 安装 webpack
  1. npm install webpack -g

四、示例

  1. 新建文件夹 webpack-sample
  2. 在 webpack-sample 下新建文件夹 app、public
  3. 在 app 目录下新建 Greeter.js、main.js、config.json
  4. 在 public 目录下新建 index.html
  5. 写入代码
  • Greeter.js
  1. let config = require('./config.json');
  2. module.exports = function () {
  3. var greet = document.createElement('div');
  4. greet.textContent = config.greetText;
  5. return greet;
  6. };
  • config.json
  1. {
  2. "greetText":"Hi there and greetings from JSON!"
  3. }
  • main.js
  1. const greeter = require('./Greeter.js');
  2. document.querySelector('#root').appendChild(greeter());
  3. console.log(12334)
  • /public/index.html
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <div id="root"></div>
  9. <p class="paragraph">12333</p>
  10. <div>xxxxxx</div>
  11. <script src="bundle.js"></script>
  12. </body>
  13. </html>
  1. 在 webpack-sample 目录下打开命令行,输入以下打包命令
  1. webpack-cli --entry ./app/main.js --output ./public/bundle.js
  1. 运行 index.html 页面,可以看到已经成功;

五、配置npm scripts

  • 前面我们通过命令行打包,需要配置一大堆参数。为了减少这种情况,我们需要配置 npm scripts

npm scripts 配置

  • 首先生成一个 package.json 文件
  • 在 package.json 中有一个 scripts 对象,在这个对象中的每一个属性都是一个可以通过 npm run 执行的命令;
  • 以上面打包示例
  1. {
  2. "name": "wbp",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1",
  8. "cmdBuild": "webpack-cli --entry ./app/main.js --output ./public/bundle.js"
  9. },
  10. "keywords": [],
  11. "author": "",
  12. "license": "ISC"
  13. }
  • 然后在 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

  1. npm install webpack-cli webpack --save-dev

6.1 配置 entry、output

  • entry(入口)是 webpack 打包的起点,它从这个文件开始查找各个模块之间的依赖
  • output(出口)是 webpack 打包后的文件输出目录和文件名;

示例:

  1. module.exports = {
  2. entry: __dirname + '/app/main.js',
  3. output: {
  4. path: __dirname + '/public', // 打包后文件存放的地方
  5. filename: 'bundle.js'
  6. }
  7. };

6.2 配置 source-map

什么是 source-map?

js 代码编译后变得可读性非常差,不利于调试;而浏览器有一种 source-map 机制,可以通过 source-map 把代码虚拟还原成打包之前的样子,这样方便调试;

webpack在打包结束后可以自动生成 source map

  • 在配置中加入 devtool 属性
  1. module.exports = {
  2. devtool: "eval-source-map", // 生成source-map
  3. entry: __dirname + '/app/main.js',
  4. output: {
  5. path: __dirname + '/public', // 打包后文件存放的地方
  6. filename: 'bundle-[hash:5].js'
  7. }
  8. };

6.3 配置打包的 npm scripts

  • 在 package.json 中配置 build 命令;
  1. {
  2. "name": "wbp",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1",
  8. "build": "webpack",
  9. "cmdBuild": "webpack-cli --entry ./app/main.js --output ./public/bundle.js"
  10. },
  11. "keywords": [],
  12. "author": "",
  13. "license": "ISC"
  14. }
  • 在命令行中执行 npm run build 即可打包

6.4 配置 dev-server

在开发的过程中我们可以让 webpack 给我们启动一个本地服务器,它可以:

  • 让浏览器监听你的代码的修改,并自动刷新显示修改后的结果;
  • 提供 AJAX 接口的代理,解决开发环境的跨域问题
  1. 安装 webpack-dev-server
  1. npm install --save-dev webpack-dev-server
  1. 在 webpack 配置中加入配置项
  1. module.exports = {
  2. devtool: "eval-source-map", // 生成 source-map
  3. entry: __dirname + '/app/main.js',
  4. output: {
  5. path: __dirname + '/public', // 打包后文件存放的地方
  6. filename: 'bundle1.js'
  7. },
  8. devServer: {
  9. contentBase: './public', // 本地服务器所加载的页面所在的目录
  10. historyApiFallback: true, // 单页面应用路由切换时不跳转
  11. inline: true, // 实时刷新
  12. port: 8080,
  13. proxy: {
  14. '/api': { // 如果接口中带有 API 标志,那么就需要开始代理
  15. target: 'http://localhost:8001',
  16. changeOrigin: true, // target 是域名的话,需要这个参数,
  17. secure: false // 设置支持 https 协议的代理,不检查安全与否
  18. }
  19. }
  20. }
  21. };
  • 配置详解
    • contentBase: ‘./public’, 本地服务器所加载的页面所在的目录
    • historyApiFallback: true, 单页面应用路由切换时不跳转
    • inline: true, // 实时刷新
    • port: 8080, 启动时的端口号
    • proxy: 代理配置
  1. 配置 npm scripts,启动 webpack 的 dev-server:
  1. {
  2. "name": "wbp",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1",
  8. "build": "webpack",
  9. "cmdBuild": "webpack-cli --entry ./app/main.js --output ./public/bundle.js",
  10. "dev": "webpack-dev-server --open"
  11. },
  12. "keywords": [],
  13. "author": "",
  14. "license": "ISC",
  15. "devDependencies": {
  16. "webpack-dev-server": "^3.7.2"
  17. }
  18. }

七、配置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;

  1. 安装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 语法
  1. / npm一次性安装多个依赖模块,模块之间用空格隔开
  2. npm install babel-core babel-loader@7.1.5 babel-preset-env babel-preset-react --save-dev
  1. 在 webpack 配置文件中加入 loader 信息;
  • 在webpack 加入 module 配置
  1. module.exports = {
  2. devtool: "eval-source-map", // 生成 source-map
  3. entry: __dirname + '/app/main.js',
  4. output: {
  5. path: __dirname + '/build', // 打包后文件存放的地方
  6. filename: 'bundle1.js'
  7. },
  8. devServer: {
  9. contentBase: './public', // 本地服务器所加载的页面所在的目录
  10. historyApiFallback: true, // 单页面应用路由切换时不跳转
  11. inline: true, // 实时刷新
  12. port: 8080,
  13. proxy: {
  14. '/api': { // 如果接口中带有 API 标志,那么就需要开始代理
  15. target: 'http://localhost:8001',
  16. changeOrigin: true, // target 是域名的话,需要这个参数,
  17. secure: false // 设置支持 https 协议的代理,不检查安全与否
  18. }
  19. }
  20. },
  21. module: {
  22. rules: [
  23. {
  24. test: /(\.jsx|\.js)$/,
  25. use: {
  26. loader: "babel-loader",
  27. options: {
  28. presets: ['env', 'react']
  29. }
  30. },
  31. exclude: /node_modules/
  32. }
  33. ]
  34. }
  35. };

7.3 配置CSS loader

CSS 也可以像 js 一样的导入进来;

  1. 安装 css-loader 和 style-loader;
    • 安装 css-loader 可以使用 @import 或者 url 等方法导入其他资源
    • style-loader 将所有计算后的样式加入页面中
  1. npm install --save-dev style-loader css-loader
  1. 在 webpack 中配置 css-loader
  1. module.exports = {
  2. devtool: "eval-source-map", // 生成 source-map
  3. entry: __dirname + '/app/main.js',
  4. output: {
  5. path: __dirname + '/public', // 打包后文件存放的地方
  6. filename: 'bundle.js'
  7. },
  8. devServer: {
  9. contentBase: './public', // 本地服务器所加载的页面所在的目录
  10. historyApiFallback: true, // 单页面应用路由切换时不跳转
  11. inline: true, // 实时刷新
  12. port: 8080,
  13. proxy: {
  14. '/api': { // 如果接口中带有 API 标志,那么就需要开始代理
  15. target: 'http://localhost:8001',
  16. changeOrigin: true, // target 是域名的话,需要这个参数,
  17. secure: false // 设置支持 https 协议的代理,不检查安全与否
  18. }
  19. }
  20. },
  21. module: {
  22. rules: [
  23. {
  24. test: /(\.jsx|\.js)$/,
  25. use: {
  26. loader: "babel-loader",
  27. options: {
  28. presets: ['env', 'react']
  29. }
  30. },
  31. exclude: /node_modules/
  32. },
  33. {
  34. test: /\.css$/,
  35. use: [
  36. {
  37. loader: 'style-loader'
  38. },
  39. {
  40. loader: 'css-loader'
  41. }
  42. ]
  43. }
  44. ]
  45. }
  46. };
  1. 写一个css文件
  • main.css
  1. * {
  2. margin: 0;
  3. padding: 0;
  4. }
  5. div {
  6. font-size: 30px;
  7. color: red;
  8. }
  1. 在main.js 中导入css
  1. import './main.css';

7.4 配置 less

配置 less-loader 以后,我们写 less webpack 会帮我们编译成 css,就不需要我们再引入 js 文件;

  1. 安装less、less-loader
  1. npm install less less-loader --save-dev

2 配置 less-loader

  1. module.exports = {
  2. devtool: "eval-source-map", // 生成 source-map
  3. entry: __dirname + '/app/main.js',
  4. output: {
  5. path: __dirname + '/build', // 打包后文件存放的地方
  6. filename: 'bundle.js'
  7. },
  8. devServer: {
  9. contentBase: './public', // 本地服务器所加载的页面所在的目录
  10. historyApiFallback: true, // 单页面应用路由切换时不跳转
  11. inline: true, // 实时刷新
  12. port: 8080,
  13. proxy: {
  14. '/api': { // 如果接口中带有 API 标志,那么就需要开始代理
  15. target: 'http://localhost:8001',
  16. changeOrigin: true, // target 是域名的话,需要这个参数,
  17. secure: false // 设置支持 https 协议的代理,不检查安全与否
  18. }
  19. }
  20. },
  21. module: {
  22. rules: [
  23. {
  24. test: /(\.jsx|\.js)$/,
  25. use: {
  26. loader: "babel-loader",
  27. options: {
  28. presets: ['env', 'react']
  29. }
  30. },
  31. exclude: /node_modules/
  32. },
  33. {
  34. test: /\.css$/,
  35. use: [
  36. {
  37. loader: 'style-loader'
  38. },
  39. {
  40. loader: 'css-loader'
  41. }
  42. ]
  43. },
  44. {
  45. test: /\.less$/,
  46. use: ['style-loader', 'css-loader', 'less-loader']
  47. }
  48. ]
  49. }
  50. };

7.5 配置 url-loader

配置 url-loader 后,我们可以导入图片;

  1. 安装 url-loader
  1. npm install url-loader --save-dev
  1. 配置 url-loader
  1. module.exports = {
  2. devtool: 'eval-source-map',
  3. entry: __dirname + '/app/main.js',
  4. output: {
  5. path: __dirname + '/public',
  6. filename: 'bundle.js'
  7. },
  8. devServer: {
  9. contentBase: __dirname + '/public',
  10. historyApiFallback: true, // 单页面应用路由切换时不请求服务器
  11. inline: true, // 实时刷新
  12. port: 8080,
  13. proxy: {
  14. '/api': { // 如果接口中带有 api,就代理转发到 target
  15. target: 'http://localhost:8001',
  16. changeOrigin: true, // 如果 target 是域名的话,需要整个参数
  17. secure: false // 不校验安全,允许访问 https
  18. }
  19. }
  20. },
  21. module: {
  22. rules: [
  23. {
  24. test: /\.(js|jsx)$/,
  25. use: {
  26. loader: 'babel-loader',
  27. options: {
  28. presets: ['env', 'react']
  29. }
  30. },
  31. exclude: /node_modules/
  32. },
  33. {
  34. test: /\.css$/,
  35. use: [ 'style-loader', 'css-loader']
  36. },
  37. {
  38. test: /\.less$/,
  39. use: ['style-loader', 'css-loader', 'less-loader']
  40. },
  41. {
  42. test: /\.(png|jpg|gif)$/,
  43. use: {
  44. loader: 'url-loader'
  45. }
  46. }
  47. ]
  48. }
  49. };

八、插件

插件(Plugins)是用来拓展 Webpack 功能的,它们会在整个构建过程中生效,执行相关的任务。Webpack 有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。

使用插件

要使用某个插件,我们需要通过 npm 安装它,然后要做的就是在 webpack 配置中的 plugins 关键字部分添加该插件的一个实例;

  • 让 webpack 打包后帮我们引入打包后的js文件;

实现以上功能需要一个插件;html-webpack-plugin,首先安装它;

  1. 安装
  1. npm install html-webpack-plugin --save-dev
  1. 引入插件
  1. let HtmlWebpackPlugin = require('html-webpack-plugin');
  1. 在 webpack 中增加一个 plugins 字段,它的值是一个数组,使用插件就是创建一个插件的实例,然后作为数组项放到 plugins 中;
  1. let HtmlWebpackPlugin = require('html-webpack-plugin');
  2. module.exports = {
  3. devtool: "eval-source-map", // 生成 source-map
  4. entry: __dirname + '/app/main.js',
  5. output: {
  6. path: __dirname + '/build', // 打包后文件存放的地方
  7. filename: 'bundle.js'
  8. },
  9. devServer: {
  10. contentBase: './public', // 本地服务器所加载的页面所在的目录
  11. historyApiFallback: true, // 单页面应用路由切换时不跳转
  12. inline: true, // 实时刷新
  13. port: 8080,
  14. proxy: {
  15. '/api': { // 如果接口中带有 API 标志,那么就需要开始代理
  16. target: 'http://localhost:8001',
  17. changeOrigin: true, // target 是域名的话,需要这个参数,
  18. secure: false // 设置支持 https 协议的代理,不检查安全与否
  19. }
  20. }
  21. },
  22. module: {
  23. rules: [
  24. {
  25. test: /(\.jsx|\.js)$/,
  26. use: {
  27. loader: "babel-loader",
  28. options: {
  29. presets: ['env', 'react']
  30. }
  31. },
  32. exclude: /node_modules/
  33. },
  34. {
  35. test: /\.css$/,
  36. use: [
  37. {
  38. loader: 'style-loader'
  39. },
  40. {
  41. loader: 'css-loader'
  42. }
  43. ]
  44. },
  45. {
  46. test: /\.less$/,
  47. use: ['style-loader', 'css-loader', 'less-loader']
  48. },
  49. {
  50. test: /\.(png|jpg|gif)$/,
  51. use: 'url-loader'
  52. }
  53. ]
  54. },
  55. plugins: [
  56. new HtmlWebpackPlugin({
  57. template: __dirname + '/public/index.html' // 指定一个模板,webpack 将会按照这个模板创建 html
  58. })
  59. ]
  60. };
  • 做完这些后,我们修改输出路径为 build;
  • 执行 npm run build

执行后我们发现在 build 目录下有一个 index.html 和 bundle.js;同时 index.html 已经自动引入了 bundle.js