欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

webpack 快速入门教程

程序员文章站 2024-03-23 15:03:16
...

webpack 是什么

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。

在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。 它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6jcc1KKp-1595555820303)(/Users/mxj/百度云同步盘/学习笔记/前端全栈/img/image-20200406095604708.png)]

官方中文文档参考:https://www.webpackjs.com/

模块打包,通俗地说就是:找出模块之间的依赖关系,按照一定的规则把这些模块组织合并为一个JavaScript文件。

webpack 的五个核心感念

名称 描述
entry 入口(Entry)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。
output 输出(Output)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。
loader Loader(加载器) 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)
plugins 插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩, 一直到重新定义环境中的变量等。
mode 通过选择 developmentproduction 之中的一个,来设置 mode 参数,你可以启用相应模式下的 webpack 内置的优化

webpack 安装与命令行打包

Webpack依赖Node.js,所以首先你要确保安装了 node.js。

node 官网

Webpack的安装分为全局安装与本地安装,推荐使用本地安装。

全局安装的Webpack,在任何目录执行webpack命令都可以进行打包。而本地安装的Webpack,必须要找到对应node_modules下的webpack命令才能执行(在使用npx或package.json的scripts的时候,会自动帮助我们寻找)。

全局安装

# 全局安装最新稳定版本
  npm install webpack webpack-cli -g

# 全局安装指定版本
  npm install aaa@qq.com4.43.0  webpack-aaa@qq.com3.3.12 -g

# 全局安装指体验版本,目前(2020-7-10)体验版本是webpack5
  npm install aaa@qq.com webpack-cli -g

本地安装

# 本地安装最新稳定版本,该命令是npm install webpack webpack-cli --save-dev的缩写
  npm i webpack webpack-cli -D

全局安装与本地安装的Webpack是可以共存的。在大多数前端项目开发的时候,是需要本地安装的。因为只进行全局安装的话,可能因为版本不一致的问题导致本地项目跑不起来。

本地安装的Webpack,如果不想拼接路径,我们可以使用命令npx webpack,或者在package.json文件里写入下面的命令并执行npm run dev。这两种方式都会自动执行node_modules下的webpack命令,不需要我们把路径拼接上。

 // ...
  "scripts": {
    "dev": "webpack"
  },
  // ...

使用方法

初始化一个npm项目并使用默认参数创建package.json文件。

npm init -y

安装了指定版本的webpack与webpack-cli。

npm install --save-dev aaa@qq.com    aaa@qq.com   

webpack是webpack核心包,webpack-cli是命令行工具包,在用命令行执行webpack的时候需要安装。

因为浏览器不支持原始 ES6 模块,所以不能直接将 ES6 的 JS 文件导入 html。我们可以通过Webpack把这两个文件打包成一个JS文件来解决这个问题。Webpack打包后,代码里就没有这种模块化语法了。

打包命令

a.js

import { name } from './b.js';  
console.log(name);

b.js

export var name = 'Jack';

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="./bundle.js"></script>
</body>
</html>

执行打包命令

npx webpack a.js -o bundle.js  

打包之后就可以把合并之前的文件删除了,即a.js、 b.js。

打包后的bundle.js代码目前是压缩后的,后面会讲解怎样不压缩打包后的代码。

我们在执行上面命令的时候,命令行控制台会出现警告信息,告诉我们没有设置’mode’项,Webpack将会使用默认的’production’。我们可以在上面的命令后面配上’mode’项,但当命令参数过长的时候,使用起来就会不方便。此时,我们可以选择使用Webpack的配置文件。

webpack 快速入门教程

webpack 配置文件

Webpack默认的配置文件是项目根目录下的webpack.config.js,在我们执行下方命令的时候,

npx webpack  

Webpack会自动寻找该文件并使用其配置信息进行打包。如果不存在会报错

webpack 快速入门教程

我们可以手动创建 webpack.config.js 文件。

  var path = require('path');  
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    mode: 'none'
  };

命令行执行npx webpack后,Webpack就开始打包了。配置文件里的代码解释:

因为Webpack是基于Node.js执行的,所以可以使用Node的功能。path是Node.js里的路径解析模块,你可以将其看成是一个JS普通对象,该对象有一些方法可以供我们使用。我们现在使用了其resolve方法,该方法的作用是将方法参数解析成一个绝对路径返回。__dirname是Node.js的一个全局变量,表示当前文件的路径。这样,path.resolve(__dirname, ”)表示的其实就是当前文件夹根目录的绝对路径。

module.exports是CommonJS模块导出语法,导出的是一个对象,该对象的属性就是Webpack打包要使用的参数。entry是Webpack构建的入口文件,我们的入口文件是a.js。output是打包后资源输出文件,其中path表示输出的路径,filename表示输出的文件名,现在我们把打包后的文件输出在当前目录的bundle.js。

mode是Webpack的打包模式,默认是’production’,表示给生产环境打包的。现在我们设置成’none’,这样代码就不会压缩了。

入口起点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqXLDlTb-1595555820306)(/Users/mxj/百度云同步盘/学习笔记/前端全栈/自动化部署/img/webpack-tutorial-1024x454.png)]

图片里箭头开始的.js文件就是Webpack构建的资源入口,然后根据这个.js文件依赖的文件,把相关联的文件模块打包到一个.js文件,本质上来说,这个打包后得到的.js文件就是Webpack打包构建的资源出口。

当然,这个.js文件通常不是我们最终希望打包出来的资源,我们希望可以拆分成JS、CSS和图片等资源。

Webpack当然提供了这样的方法。在构建的时候,我们可以通过Webpack的预处理器loader和插件plugin等进行干预,把一个.js文件变成JS、CSS和图片等资源。

可以通过修改 webpack 配置的 entry 属性,来指定一个或多个入口路径。默认为 ./src。

webpack.config.js

module.exports = {
  entry: './path/to/my/entry/file.js' //入口路径
};

webpack 基础目录(context)

context 官方称为基础目录,在Webpack中表示资源入口entry是从哪个目录为起点的。context的值是一个字符串,表示一个绝对路径。

下面的配置表示从工程根目录下src文件夹下的js文件夹里的a.js开始打包。

var path = require('path');  
  module.exports = {
    context: path.resolve(__dirname, './src'),
    entry: './js/a.js',
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    mode: 'none'
  };

一般我们不会去设置context,在我们没有设置context的时候,它是当前工程的根目录。

资源入口 entry

Webpack资源入口entry代表的路径,是相对路径。目前我们使用的entry都是字符串形式的,其实它还可以是数组、对象和函数形式。

  • 字符串

    字符串形式的我们已经在之前使用过了,是最简单的形式,表示打包的入口JS文件。

  • 数组

    module.exports = {
        entry: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
      };
    

    它表示的含义是数组最后一个文件是资源的入口文件,数组其余文件会预先构建到入口文件。

    上面的配置和下面是等效的

    a.js

      import 'core-js/stable';
      import 'regenerator-runtime/runtime';
    

    webpack.config.js

    module.exports = {
        entry: './a.js',
      };
    

    数组形式的入口本质还是一个入口。

  • 对象

    入口entry是对象形式的又称之为多入口配置,本质上打包后生成多个JS文件。

    var path = require('path');  
      module.exports = {
        entry: {
          app: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
          vendor: './vendor'
        },
        output: {
          path: path.resolve(__dirname, ''),
          filename: '[name].js'
        },
        mode: 'none'
      };
    

    上方的配置分别从两个入口文件打包,每个入口文件各自寻找自己依赖的文件模块打包成一个JS文件,最终得到两个JS文件。

  • 函数

    函数形式的入口,Webpack取函数返回值作为入口配置,返回值是上述3种之一即可。

    函数形式的entry,可以用来做一些额外的逻辑处理,不过在自己搭脚手架的很少使用。

常见场景

分离 应用程序(app) 和 第三方库(vendor) 入口

webpack.config.js

const config = {
  entry: {
    app: './src/app.js',
    vendors: './src/vendors.js'
  }
};

多页面应用程序

webpack.config.js

const config = {
  entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
  }
};

这个告诉 webpack 需要 3 个独立分离的依赖图(如上面的示例)。

在多页应用中,每当页面跳转时服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载。

输出

output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个 output 字段,来配置这些处理过程:

webpack.config.js

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'), //输出路径
    filename: 'my-first-webpack.bundle.js' //用于输出文件的文件名。
  }
};

配置 output 选项可以控制 webpack 如何向硬盘写入编译文件。注意,即使可以存在多个入口起点,但只指定一个输出配置。

publicPath

publicPath 指定静态资源路径,当使用 webpack 打包时会将打包文件放进指定的目录中。

当使用 webpack-dev-server 时可以不用设置publicPath,因为该插件内置的库会自动在根目录下生成 index.html。

webpack-dev-server 会把打包后的文件放到项目的根目录下,文件名是在output配置中的filename. 但是当有publicPath 配置的时候,就不一样了。Webpack 会把所有的文件打包到publicPath指定的目录下,就是相当于在项目根目录下创建了一个publicPath目录, 然后把打包成的文件放到了它里面,只不过我们看不到而已, 文件名还是output配置中的filename。

模式

提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。

语法

module.exports = {
  mode: 'production'
};

或者从 CLI 参数中传递:

webpack --mode=production

支持以下字符串值:

选项 描述
development 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPluginNamedModulesPlugin
production 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin.

loader

Loader是Webpack生态里一个重要的组成,我们一般称之为预处理器。

loader 用于对模块的源代码进行转换。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!因为 webpack 只解析 js/json 格式的文件,所以当需要给 css、图片打包时需要用到 loader。

loader 可以使你在 import 或"加载"模块时预处理文件。

安装 loader

这里我们安装两个loader,分别是css-loader与style-loader。

其中css-loader是必需的,它的作用是解析CSS文件,包括解析@import等CSS自身的语法。它的作用也仅仅是解析CSS文件,它会把CSS文件解析后,以字符串的形式打包到JS文件中。不过,此时的CSS样式并不会生效,因为我们需要把CSS插入到html里才会生效。

此时,style-loader就来发挥作用了,它可以把JS里的样式代码插入到html文件里。它的原理很简单,就是通过JS动态生成style标签插入到html文件的head标签里。

npm install --save-dev css-loader
npm install --save-dev style-loader

// 合并写法
npm install -S css-loader style-loader 

在 webpack 的配置中 loader 有两个目标:

  1. test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
  2. use 属性,表示进行转换时,应该使用哪个 loader。

webpack.config.js

const path = require('path');

const config = {
  output: {
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { 
       test: /\.css/, //正则匹配将要打包的文件格式
       use: ['style-loader', 'css-loader'] //使用的加载器
      }
    ]
  }
};

module.exports = config;

可以看到,我们需要对配置项新增module,该项是一个对象,其rules里是我们对各个类型文件的处理规则配置。

use值是一个数组,每一项是一个loader。loader的执行顺序是从后向前执行,先执行css-loader,然后把css-loader执行的结果交给style-loader执行。

现在我们执行npx webpack来完成打包,然后在浏览器打开index.html,发现CSS生效了。

使用

  • webpack配置(推荐):在 webpack.config.js 文件中指定 loader。

  • 内联:在每个 import 语句中显式指定 loader。

    import Styles from 'style-loader!css-loader?modules!./styles.css';
    
  • cli

    你也可以通过 CLI 使用 loader:

    webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
    

    这会对 .jade 文件使用 jade-loader,对 .css 文件使用 style-loadercss-loader

plugins

插件目的在于解决 loader 无法实现的其他事

webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。

用法

由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。

配置

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const path = require('path');

const config = {
  entry: './path/to/my/entry/file.js',
  output: {
    filename: 'my-first-webpack.bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader'
      }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

webpack 初体验

初始化配置

(1)初始化 package.json

npm init

(2)下载并安装 webpack

npm install webpack webpack-cli -g //全局安装
npm install webpack webpack-cli -D //局部安装

当电脑上全局安装 webpack 时也需要局部安装,因为在运行的项目所使用的 webpack 版本可能低于当前电脑中的版本,这时需要安装指定版本的 webpack

npm install aaa@qq.com

编译打包应用

  1. 创建文件

  2. 运行指令

    开发环境指令:webpack src/js/index.js -o build/js/built.js --mode=development
    功能:webpack 能够编译打包 js 和 json 文件,并且能将 es6 的模块化语法转换成浏览器能识别的语法。
    
    生产环境指令:webpack src/js/index.js -o build/js/built.js --mode=production
    功能: 在开发配置功能上多一个功能,压缩代码。
    
  3. 结论

    webpack 能够编译打包 js 和 json 文件。
    能将 es6 的模块化语法转换成浏览器能识别的语法。 能压缩代码。

  4. 问题
    不能编译打包 css、img 等文件。
    不能将 js 的 es6 基本语法转化为 es5 以下语法。

开发环境基本配置

打包样式资源

(1)新建文件
webpack 快速入门教程

(2)下载安装包

npm i css-loader style-loader less-loader less -D

(3)修改配置文件

// resolve 用来拼接绝对路径的方法 const { resolve } = require('path');
module.exports = {
// webpack 配置
// 入口起点
entry: './src/index.js', 
// 输出
output: {
// 输出文件名
filename: 'built.js',
// 输出路径
// __dirname nodejs 的变量,代表当前文件的目录绝对路径 path: resolve(__dirname, 'build')
},
// loader 的配置 module: {
rules: [
// 详细 loader 配置
// 不同文件必须配置不同 loader 处理 {
// 匹配哪些文件
test: /\.css$/,
// 使用哪些 loader 进行处理 use: [
// use 数组中 loader 执行顺序:从右到左,从下到上 依次执行
// 创建 style 标签,将 js 中的样式资源插入进行,添加到 head 中生效 'style-loader',
// 将 css 文件变成 commonjs 模块加载 js 中,里面内容是样式字符串 'css-loader'
] },
      {
        test: /\.less$/,
        use: [
'style-loader', 'css-loader',
// 将 less 文件编译成 css 文件 // 需要下载 less-loader 和 less 'less-loader'
] }
] },
// plugins 的配置 plugins: [
// 详细 plugins 的配置 ],
// 模式
mode: 'development', // 开发模式 // mode: 'production'
}

(4)运行指令 webpack

打包 html 资源

(1)新建文件
webpack 快速入门教程

(2)安装命令

npm install --save-dev html-webpack-plugin

(3)修改配置

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
// loader 的配置 ]
}, plugins: [
// plugins 的配置
// html-webpack-plugin
// 功能:默认会创建一个空的 HTML,自动引入打包输出的所有资源(JS/CSS) // 需求:需要有结构的 HTML 文件
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
      template: './src/index.html'
    })
],
  mode: 'development'
};

(4)执行指令 webpack

打包图片资源

(1)新建文件
webpack 快速入门教程

(2)下载安装包

npm install --save-dev html-loader url-loader file-loader

(3)修改配置

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
{
test: /\.less$/,
// 要使用多个 loader 处理用 use
use: ['style-loader', 'css-loader', 'less-loader']
}, {
// 问题:默认处理不了 html 中 img 图片 // 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个 loader
// 下载 url-loader file-loader loader: 'url-loader', options: {// 图片大小小于8kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs // 解析时会出问题:[object Module]
// 解决:关闭 url-loader 的 es6 模块化,使用 commonjs 解析
esModule: false,
// 给图片进行重命名
// [hash:10]取图片的 hash 的前 10 位
// [ext]取文件原来扩展名
name: '[hash:10].[ext]'
} },
{
test: /\.html$/,
// 处理 html 文件的 img 图片(负责引入 img,从而能被 url-loader 进行处理) loader: 'html-loader'
} ]
}, plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
}) ],
  mode: 'development'
};

(4)运行指令: webpack

打包其他资源

其他资源值的是除 css、图片、html 之外的资源

(1)新建文件

webpack 快速入门教程

(2)修改配置

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源) {
// 排除 css/js/html 资源
exclude: /\.(css|js|html|less)$/, loader: 'file-loader',
options: {
          name: '[hash:10].[ext]'
        }
} ]
}, plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
})
],
  mode: 'development'
};    

devserver

修改配置

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源) {
// 排除 css/js/html 资源
exclude: /\.(css|js|html|less)$/,
       loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]'
        }
} ]
}, plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
}) ],
  mode: 'development',
   devServer: {
  // 项目构建后路径
  contentBase: resolve(__dirname, 'build'), // 启动 gzip 压缩
  compress: true,
  // 端口号
  port: 3000,
  // 自动打开浏览器
  open: true
  } };

运行指令: npx webpack-dev-server