webpack4.0 的配置及简单使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/FlowGuanEr/article/details/100651819

webpack

学习 webpack 能极大的扩充前端开发视野,所以推荐前端开发工程师,使用 webpack 构建工具。

webpack 4.0 相对于之前的版本,有了更多的变化,开发速度更快,大型项目能节约 90% 的构建时间。

webpack 4.0 内置了更多的默认配置,变更了许多 API

webpack 的简单介绍

在面向对象的编程思想出现以前,我们都是使用面向过程的方式做网页开发的。要向页面中添加一些内容,必须要挨个创建,挨个编写内容,然后挨个添加,如果页面中的内容一多,就要编写很多雷同的代码,很容易形成代码冗余。

这个时候就出现了面向对象的编程思想,可以把页面中的内容按模块分装单独的业务逻辑文件。

面向对象要求将每个模块封装成对应的类,想要使用这个模块(如table)时,从这个类中实例化一个对象即可,大大提高了代码的可维护性。

但是如果划分的模块很多很大,每个类要单独写在一个 JS 文件中,这样一个页面中引入的 JS 文件次数就会变多,页面会产生代码冗余,并且会增加服务器的加载负荷。而且这样加载时,无法准确的知道项目的层级关系,还是不好管理。报错不好调试。

所以我们希望,如果要在某个入口 JS 文件中使用其他 JS 文件的代码,不用将这么多的 JS 文件都引入同一个 HTML,在 JS 入口文件中自己引入其他 JS 文件,也就是 JS 文件之间可以互相引入,在 HTML 页面中只引入逻辑入口文件。

这样做的好处:

  • 不需要在 HTML 中引入很多的 JS 文件,提高文件加载速度。
  • 文件和文件之间的依赖关系会变得很明确,降低出错率,提高代码的可维护性。

ES6 Module 的语法可以提供这些功能:

import Header from './Header'
import Sidebar from './Sidebar'
import Content from './Content'
/*
...
 */

但是浏览器并不识别这样的语法,需要做特殊的设置。 除了可以将 <script> 标签的 type 属性 设置为 module 外,还可以使用 webpack 来解析这样的语法,解析成浏览器能识别的语法格式(webpack 不仅可以打包 JS 文件,还可以打包其他任意文件,在框架中的使用可以体现其功能的强大)。

webpack 到底是什么?

核心定义:webpack is a module bundler

webpack 是一个模块打包工具。

为了能让代码具备更高的复用性、可读性和维护性,我们可以将网页中的内容划分成不同的模块,使用 ES6 module
语法编写脚本,最后使用 webpack 打包工具解析 import 语法,打包 JS 脚本,生成一个可以被浏览器识别的 JS 脚本文件。

webpack 也可以识别 CommonJS 模块引入规范、CMDADM 模块规范。

因为 webpack 是模块打包工具,所以它可以识别任何模块封装代码。

webpack 最开始只打包 JS 的模块。但是随着技术的发展,JS 可以打包任何形式的模块文件,这样的代码常出现在框架中。

webpack 环境搭建

webpack 是基于 node.js 开发的模块打包工具,它本质上是由 node 实现的,要使用 webpack,必须先安装 Node.js 的环境。

然后在指定的项目文件目录中安装 webpack

一、npm init

会在项目的目录文件中生成一个 package.json 的项目文件,这个文件描述了这个项目的初始信息。

文件初始内容:

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "private": true, // 这个工具仅供自己使用,不会被发布出去
  "author": "Guan Er",
  "license": "ISC" // 是否开源
}

二、全局或局部安装 webpack

npm i webpack webpack-cli -g

npm i webpack webpack-cli --save-dev

验证 webpack 安装成功: webpack -v

一般情况下不建议全局安装 webpack,以避免版本号变更带来的各种问题。

在项目中安装 webpack 成功之后,会在项目的目录文件下生成一个 node_modules 的文件夹,其中包含了 webpack 和其依赖包的 JS 文件。

如果是局部安装,就不能使用 webpack 命令(因为这代表全局查找 webpack),node 提供了 npx 命令运行 webpack

如:
npx webpack -v;

npx 命令帮助我们在当前项目的目录中找 webpack

webpack 的简单配置

没有配置文件时也可以打包,只不过要指定打包的文件,还要在命令行写一些其他的。没有配置文件时,我们使用的是官方提供的默认配置文件。

一、基础配置

在项目的根目录中新建 webpack.config.js 做配置:

// 引入node提供的 path 对象,来配置打包好的文件的路径
const path = require('path');

// webpack 配置文件
module.exports = {
  entry: './index.js', // 指定要打包的入口文件路径(根据入口文件和配置文件的相对目录自拟)
  output: { // 打包好的文件的配置
    filename: 'over.js', // 打包好的文件的名称
    // __dirname 指 webpack.config.js 所在的目录
    // mydist 文件夹的绝对路径是和 webpack.config.js 同级父目录
    // 如果 path 不设置,那么打包之后的文件夹默认叫 dist,文件名默认叫 main.js
    path: path.resolve(__dirname, 'mydist') // 打包好的文件的路径
  }
};

以上配置文件的意义是:当在命令行输入 npx webpack 命令并执行时,会将 webpack.config.js 文件同级目录的 index.js 打包,打包之后会在 项目的根目录下生成一个 mydist 文件夹,该文件夹中包含了一个 over.js 文件,是打包之后的脚本文件,在 html 中引入的脚本是 mydist 中的 over.js

注:

  • 当使用 npx webpack 命令打包时,要求配置文件必须叫 webpack.config.js
  • 如果配置文件叫其他名称(如 config.js),还想正常打包,可以使用命令 npx webpack --config config.js

一般情况下,我们的项目目录如下:

project                      // 根目录
  node_modules               // webpack 及其依赖包
  dist                       // 打包之后的目录
    index.html               // 项目的结构入口
    main.js                  // 打包之后的 js 文件,要引入到 index.html 中
  src                        // 源代码列表
    index.js
  package.json
  package-lock.json
  webpack.config.js

二、利用 npm script 简化打包代码

有时候命令行的命令代码过多,执行时比较麻烦,我们可以在 package.json 中的 script 做命令配置。
在 package.json 中,找到 scripts 配置对象,可以做命令的配置

// package.json
{ 
  ...
  "scripts": {
    // 运行 npm run start 时,运行 package.json 中的 scripts 对象中的 start 命令,会执行 webpack命令,此处的 webpack 可以不加 npx 修饰,会默认寻找当前目录下的 webpack 命令,如果当前目录没有,再寻找全局的 webpack
    "start": "webpack"
  },
  ...
}

webpack-cli:

  • 使我们在命令行中正确的运行 webpack 的命令。如果不安装这个包,就无法在命令行中使用 npx webpack 这样的命令。

三、打包过程中容易出现的问题

打包时会遇到一个警告,告诉我们没有指定配置环境。

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

需要在配置文件中指定 mode

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

mode 没有设置时,底层打包时的默认值是 productionmode 设置为 production,打包之后的 js 文件是被压缩的,如果不想打包成压缩文件,可以将 mode 设置为 development

Webpack 打包示例

一、使用 Loader 打包图片

index.js 中引入图片:

import avatar from './1.png

会直接报错:

ERROR in ./src/1.png 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
 @ ./src/index.js 4:0-28

webpack 默认指打包 js 文件,无法打包 png,想要实现打包,需要我们做配置。

安装一个打包图片时需要的工具:

npm i file-loader -D

然后在 webpack.config.js 配置文件中做配置:

// 引入node提供的 path 对象,来配置打包好的文件的路径
const path = require('path');

// webpack 配置文件
module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: { // 打包非 js 文件时的配置
    rules: [{
      // 打包图片时,使用 file-loader 工具
      test: /\.(png|gif|jpe?g)$/,
      use: {
        loader: 'file-loader'
      }
    }]
  }
};

配置好之后重新打包,就不会再报错,并且在 dist 目录下,自动生成了一个新的图片。

avatar 变量就代表 dist 目录下的图片的文件名, 可以在 JS 代码中直接使用。

Loader 其实是 webpack 打包其他类型文件的解决方案。webpack 官方有非常完整的 Loader 体系,为各种类型文件的打包提供了解决方案。

1. file-loader

打包其他类型文件时的更多配置:

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.(png|gif|jpe?g)$/,
      use: {
        loader: 'file-loader',
        // 打包时的其他配置项:
        options: {
          // 打包之后的图片名称: 原文件名.原后缀名
          name: '[name].[ext]', // placeholder 占位符配置法
          outputPath: 'images/' // 设置文件打包之后的父级目录
        }
      }
    }]
  }
};

在上面的示例中,我们把 [name][ext] 称为占位符,占位符代表预留好的一些代表特殊功能的词组,类似于代码中的关键词。
webpack 官方提供的占位符里列表非常详细

2. url-loader

先在项目中安装 url-loader

npm i url-loader -D

安装之后将 webpack.config.js 中的图片 loader 改为 url-loader,重新打包,会发现打包依旧可以成功,但是图片并没有被打包到 dist 文件夹下。

但是图片依旧正常显示。

原因是当使用 url-loader 进行打包时,webpack 会将图片打包成一个 base64 的字符串,放在 main.js 中,最终返回给 import 的变量。

这样打包的好处是不用再发送请求生成一个图片,但是也有弊端,就是当图片比较大时,生成的 base64 的字符串也会非常长。这种情况可以给当前的options
添加一个 limit,规定 url-loader 打包的图片的最大字节数,超出这个字节数会使用 file-loader 打包。

options: {
  name: '[name].[ext]',
  outputPath: 'images/',
  limit: 1024 // 大于 1k 的图片使用 file-loader 打包
}

二、使用 Loader 打包样式文件

1. 打包 css 文件

在项目的 src 目录下新建一个 index.css 文件,在其中写入任意的 css 代码。

然后在 index.js 中通过 import 引入 css

...
import './index.css'
...

Vue 的脚手架中,这样的代码就可以直接生效,因为 Vue 脚手架底层已经对 css 的打包做了配置。我们在我们的项目中直接打包会出错,要像上面的图片打包一样,对 css 的打包做配置。

打包 css 样式文件需要使用到 style-loadercss-loader,所以要先安装它们。

npm i style-loader css-loader -D

webpack.config.js 文件中做出配置:

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.(png|gif|jpe?g)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 1024 
        }
      }
    },{
      test: /\.css$/,
      // 打包 css 文件时,需要两个 loader,use 要设置成数据,不能是对象
      use: ['style-loader', 'css-loader']
    }]
  }
};

最后使用 npm run start 打包文件(这里要运行的是 package.json 中配置好的 webpack 打包命令)。

打包之后 css 样式就能生效于 html

css-loader 会分析出若干个 css 文件之间的关系,然后根据 css 的模块引入 @import 引入链,将若干个 css 文件合并成一段 css 代码。

可以在 src 目录下再新建一个 avatar.css 文件,然后在 index.css 中引入:

@import './avatar.css'
/* 
index.css 的其他样式代码列表
 */

style-loader 会将 css-loader 生成的 css 代码挂载在页面的 <head> 标签中。

打包之后页面的 <head> 标签中就会有一对 <style> 标签,其中有所有的打包成功的 css 代码。

2. 打包 lessscss 文件

在项目的根目录下新建一个 index.scss 文件(可以将刚刚新建的 index.cssavatar.css 删除),然后写入一些 scss 代码:

body {
  img {
     border-radius: 50%;
  }
}

将其引入到 index.js 中:

...
import './index.scss'
...

同样的,需要安装对应的 loader(官方文档提示,打包 scss 文件时,需要安装 sass-loadernode-sass 两个包),然后在 webpack.config.js 中做一些配置,然后才可以对其进行打包。

npm i sass-loader node-sass -D

配置:

// 在 rules 中增加 scss 文件的打包配置
{
  test: /\.scss$/,
  use: [
    'style-loader',
    'css-loader',
    'sass-loader'
  ]
}

注:
loader 的执行有严格的顺序,如果一种文件的打包需要使用到很多种 loader,那么先执行后配置的 loader,再执行先配置的 loader

3. 使用 postcss-loader 为样式自动添加样式前缀

安装:

npm i postcss-loader -D

还需要安装一个 autoprefixer 的插件:

npm i autoprefixer -D

然后在项目根目录下新建一个 postcss.config.js,要做一些配置:

module.exports = {
  plugins: [
    require('autoprefixer') // postcss 要使用的一个插件
  ]
};

然后在 webpack.config.js 中配置:

{
  test: /\.scss$/,
  use: [
    'style-loader',
    'css-loader',
    'sass-loader',
    'postcss-loader'
  ]
}

4. css-loader 的其他配置项

加入在 index.scss 中又引入了一个 header.scss 文件。

这种情况在直接打包时,不会使用经过 postcss-loadersass-loader ,而直接被 css-loader 打包,如果希望 header.scss 也能按顺序被 postcss-loadersass-loader 打包,那就在 css-loader 中设置 importLoaders 值,需要经过几个 Loader,就设置几。

{
  test: /\.scss$/,
  use: [
    'style-loader',
    // 如果一个 loader 要做一些除默认配置之外的配置
    // 那么在 use 中的表现形式应该是个对象
    {
      loader: 'css-loader',
      // css-loader 的其他配置项
      options: {
        importLoaders: 2
      }
    },
    'sass-loader',
    'postcss-loader'
  ]
}

5. css 打包模块化

将样式直接引入 index.js 打包之后,样式会全局生效,这很容易产生问题,不同模块的样式可能会互相影响、覆盖。

webpack 提供一个 css-module 的功能,让指定样式只生效于指定结构。

src 目录列表:

header.scss
content.scss
header.js
content.js
index.js

代码:

// header.scss
.header {
  width: 100%;
  background: #024987;
  h2 {
    color: #f00
  }
}
// content.scss
.content {
  width: 100%;
  background: #eee;
  h2 {
    color: #1E9FFF;
  }
}
// header.js
import HeaderStyle from './header.scss'

export default function() {
  var dom = document.getElementById('root');
  var el = document.createElement('div');
  el.className = HeaderStyle.header;
  el.innerHTML = '<h2>I am header</h2>';
  dom.appendChild(el);
}
// content.js
import ContentStyle from './content.scss'

export default function() {
  var dom = document.getElementById('root');
  var el = document.createElement('div');
  el.className = ContentStyle.content;
  el.innerHTML = '<h2>I am content</h2>';
  dom.appendChild(el);
}
// index.js
import Header from './header'
import Content from './content'

Header();
Content();

为了能让这种样式代码按模块生效的功能打包成功,需要在 webpack.config.js 中做出相对应的配置:

{
  test: /\.scss$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        importLoaders: 2,
        modules: true // 开启 css-module 功能
      }
    },
    'sass-loader',
    'postcss-loader'
  ]
}

6. 打包字体文件

src 文件夹下新建一个 font 文件夹并放入一些字体文件。

font
  iconfont.eot
  iconfont.svg
  iconfont.ttf
  iconfont.woff

src 下新建 index.scss 并做字体设置:

@font-face {
  font-family: layui-icon;
  src: url(./font/iconfont.eot?v=240);
  src: url(./font/iconfont.eot?v=240#iefix) format('embedded-opentype'), url(./font/iconfont.svg?v=240#iconfont) format('svg'), url(./font/iconfont.woff?v=240) format('woff'), url(./font/iconfont.ttf?v=240) format('truetype');
}

.icon {
  font-family: iconfont;
}

.icon-reply-fill:before{ content:"\e611" }
.icon-set-fill:before{ content:"\e614" }

然后在稍微修改一下 index.js 中的代码:

import Header from './header'
import Content from './content'
import IndexStyle from './index.scss'

Header();
Content();

var newEl = document.createElement('div');
newEl.classList.add(IndexStyle['icon-reply-fill']);
newEl.classList.add(IndexStyle['icon']);

document.getElementById('root').appendChild(newEl);

如果想让上面的代码能正常打包并生效,需要在 webpack.config.js 中对字体文件的打包做出配置:

// 在 rules 中新添加一个对象
{
  test: /\.(eot|ttf|svg|woff)$/,
  use: {
    loader: 'file-loader', // 打包字体文件需要的 file-loader
    options: {
      outputPath: 'font/' // 打包之后的字体文件在 dist 目录中的路径
    }
  }
}

然后打包项目,再运行,字体文件就能正常生效。

三、plugins 工具的简单使用

plugins 的设置能让打包过程更便捷,它相当于一个自动化打包工具,有很多打包过程如果不做配置,还是需要我们手动去修改或者书写代码,plugins 的作用就是让一些代码可以自动化的生成或修改。让 webpack 的使用变得更加便捷。

webpack 官方提供了非常完善的 plugins 体系,我们下面以 html-webpack-plugin 做示范。

一般情况下,我们在项目研发中,会有一个 HTML 源代码入口文件,项目上线时,需要上线打包之后 dist 目录中的代码。那在打包时,我们也希望在 dist 目录中自动生成一个 html 文件,其中保留源代码结构入口中的所有内容,并且还将 dist 中的脚本直接引入到这个 html 文件中。

html-webpack-plugin 就可以实现这样的功能。

可以将示例项目中的 dist 目录先删除,然后在 src 目录中新建 index.html 文件,在其中写一些初始结构代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title></title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

安装:

npm i html-webpack-plugin -D

配置:

// webpack.config.js

const path = require('path');
// 要是用插件,需要现在配置文件中引入
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: {...},
  plugins: [new HtmlWebpackPlugin({
    template: 'src/index.html' // 结构模板
  })]
};

然后打包,会在 dist 目录中自动生成一个 index.html 文件,这个文件中有源代码结构文件中的所有结构代码,逻辑入口 main.js 也被直接引入其中了。

plugins 可以在 webpack 运行到某个时刻时,自动执行一些动作。

参考资料
webapck 官方文档
Dell Lee 的 webpack4.0视频课程

猜你喜欢

转载自blog.csdn.net/FlowGuanEr/article/details/100651819