登录
原创

Webpack深度学习(基础篇)

发布于 2021-04-26 阅读 613
  • 前端
  • Webpack
原创

1.什么是weack?

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

2.webpack核心概念

  • 入口(entry)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
  • 出口(output)告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist。
  • loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
  • 插件(plugins)在webpack构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要做的事情。

3.初始化项目

新建文件夹
使用 npm init 进行初始化,也可以使用yarn。初始化会生成一个package.json的文件。
package.json属性说明

    name - 包名.
    version - 包的版本号。
    description - 包的描述。
    homepage - 包的官网URL。
    author - 包的作者
    contributors - 包的其他贡献者。
    dependencies / devDependencies - 生产/开发环境依赖包列表。它们将会被安装在 node_module 目录下。
    main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
    keywords - 关键字

webpack安装,需要安装webpack,webpack-cli

npm install webpack webpack-cli --save-dev

本文编写时webpack版本为5.35.0,webpack-cli版本为3.3.12。

1. webpack配置文件

webpack.config.js就是webpack的默认配置文件,我们可以自定义配置文件,比如文件的入口,出口。

const path = require('path')
module.exports = {
    entry : './index.js',
    output : {
        filename : 'bundle.js',
        path : path.join(__dirname, 'dist')
    }
}

这个就是最基本的配置,打包一个index.js文件,也就是entry,output打包的入口,出口配置信息。在命令行中运行npx webpack,就会去找webpack.config.js文件中的配置信息。

2. npm scripts

当我们用vue, react时,我们都是执行 npm run dev,npm run start之类的命令,那它是如何执行webpack命令的呢。我们只需要在package.json中写下如下信息即可。

"scripts": {
    "dev": "webpack --config webpack.config.js"
 },

当我们执行npm run dev命令时会去package.json文件中找到scripts中的dev字段。这行代码的意思是执行webpack.config.json文件中配置的参数。

4.各参数基本配置

1. 入口entry

(1) 单入口语法:
用法:entry: string|Array<string>

webpack.config.js
最简写形式:

entry: './src/index.js'

当然还可以写成数组的形式

entry: ['./src/entry.js', './src/entry2.js']  

向 entry 属性传入「文件路径(file path)数组」将创建“多个主入口(multi-main entry)”。在你想要多个依赖文件一起注入,并且将它们
的依赖导向(graph)到一个“chunk”时,传入数组的方式就很有用。

(2) 多入口写法:
用法:entry: {[entryChunkName: string]: string|Array<string>}

webpack.config.js

entry: {
  a: "./app/entry-a",
  b: ["./app/entry-b1", "./app/entry-b2"]
}

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

 entry: {
  app: './src/app.js',
  vendors: './src/vendors.js'
 }

从表面上看,这告诉我们 webpack 从 app.js 和 vendors.js 开始创建依赖图(dependency graph)。这些依赖图是彼此完全分离、互相独
立的(每个 bundle 中都有一个 webpack 引导(bootstrap))。这种方式比较常见于,只有一个入口起点(不包括 vendor)的单页应用程
序 (single page application)中。

多页面应用程序

entry: {
  pageOne: './src/pageOne/index.js',
  pageTwo: './src/pageTwo/index.js',
  pageThree: './src/pageThree/index.js'
}

2. 出口(output)

用法:
webpack.config.js

 output: {
   filename: 'bundle.js', //输出文件的文件名
   path: '/home/proj/public/assets' // 目标输出目录 path 的绝对路径
 }

当有多个入口时:

 {
   entry: {
     app: './src/app.js',
     search: './src/search.js'
   },
   output: {
     filename: '[name].js',
     path: __dirname + '/dist'
   }
}

入口为app, search,出口会输出./dist/app.js, ./dist/search.js。

3. 模式(mode)

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

 mode: 'development'

模式支持两种:development开发模式和production生产模式。

4. loader

官网解释:loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建
工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或
将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!
说明一下因为在浏览器中很多格式的文件是不能识别的,所以loader的作用相当于翻译官,将其他格式文件翻译成浏览器可以识别的文件格式。

用法:
webpack.config.js

 module: {
   rules: [
     { test: /\.css$/, use: 'css-loader' },
     { test: /\.ts$/, use: 'ts-loader' }
   ]
}

解释一下:
loader中主要使用rules对loader进行规则定义,其中test用于检测以xxx格式结尾的文件,use用于使用一种或多种loader去处理文件。

loader 特性
(1)loader支持链式调用,从后往前调用loader

 module: {
   rules: [
     { test: /\.css$/, use: ['style-loader', 'css-loader']}
   ]
}

在上面的loader调用中先会执行css-loader,然后执行style-loader.

(2)loader支持options配置

 module: {
  rules: [
   {
     test: /\.css$/,
     use: [
       { loader: 'style-loader' },
       {
         loader: 'css-loader',
         options: {
           modules: true
         }
       }
     ]
   }
 ]
}

5. 插件(plugins)

官网解释:插件是 webpack 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上!插件目的在于解决
loader 无法实现的其他事。
用法:
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;

5. 管理资源

0.起步

首先我们创建一个目录,初始化 npm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack):

mkdir webpack-demo && cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev

现在我们将创建以下目录结构、文件和内容:

 webpack-demo
  |- package.json
  |- /dist
    |- index.html
  |- /src
    |- index.js

src/index.js

function add(x,y) {
  return x+y;
}
console.log(add(2,3));

dist/index.html

<!doctype html>
<html>
  <head>
    <title>起步</title>
  </head>
  <body>
    <script src="main.js"></script>
    <h1>webpack</h1>
  </body>
</html>

执行 npx webpack,会将我们的脚本作为入口起点,然后 输出 为 main.js。打开html会看到网页上的webpack,同时打开控制台会输出5。
接下来我们自己配置webpack,新建webpack.config.js文件。

webpack-demo
  |- package.json
+ |- webpack.config.js
  |- /dist
    |- index.html
  |- /src
    |- index.js

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
};

执行 npx webpack --config webpack.config.js会在dist文件下输出main.js。

1.处理样式文件

webpack不能直接处理样式文件,所以需要对应的loader去处理。比如.css文件就需要style-loader, css-loader,如果是.less文件就需要style-loader, css-loader, less-loader,考虑到兼容性的问题还需要postcss-loader。同理如果是.scss也需要对应的loader。
处理css文件,需要安装一下loader

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

const path = require('path');
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: '[name].js',
        // __dirname nodejs的变量,代表当前文件的目录绝对路径
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                      // use数组中loader执行顺序:从右到左,从下到上 依次执行
                      // 创建style标签,将js中的样式资源插入进行,添加到head中生效
                      'style-loader',
                      // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
                      'css-loader'
                ]
            }
        ]
    }
};

新建一个css文件,src/index.css

webpack-demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- main.js
    |- index.html
  |- /src
+   |- style.css
    |- index.js
// src/index.css
body{
    background: blue;
    color: red;
}

引入到src/index.js

import ./index.css

每次在命令行输入npx webpack --config webpack.config.js太长了,我们在package.json配置scripts字段。

"scripts":{
  "build": "webpack --config webpack.config.js"
}

这样以后打包只需输入npm run build即可。
现在执行npm run build,打开index.html页面会发现页面背景色和文字颜色都变了,那么css文件即生效了。
同理处理less文件也做类似操作。
新建一个less文件,src/index.less

webpack-demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- main.js
    |- index.html
  |- /src
+   |- index.less
    |- index.css
    |- index.js
// src/index.less
h1: {
   font-weight: 'bold'
}

引入到src/index.js

import './index.less'

处理less文件需下载less-loader,less

npm install less-loader less --save-dev

webpack.config.js

module: {
    rules: [
       {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          // 将less文件编译成css文件
          // 需要下载 less-loader和less
          'less-loader'
        ]
      }
    ]
}

执行npm run build, 打开html即可看到h1标签文字加粗。

2. 处理html文件

首先调整文件目录结构

webpack-demo
  |- package.json
  |- webpack.config.js
  |- /src
    |- index.js
    |- index.html

src/index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack</title>
</head>

<body>
  <h1>hello html</h1>
</body>

</html>

实际开发中我们不会再dist文件下手动新建html文件,而是会在src下新建html文件,dist文件是我们打包完之后自动生成的。
想要自动生成html文件就需要用到html-webpack-plugin插件来帮我们完成这件事。首先先下载插件:

npm install html-webpack-plugin -D 

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: '[name].js',
    path: 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'
    })
  ]
};

执行npm run build命令,可以看到新建的dist文件下的index.html文件,并且其中自动插入了 <script> 脚本,引入的是我们打包之后的 js 文件。在浏览器打开html文件即可看到html文件的内容。

3. 处理图片资源

处理图片资源可以下载url-loader和file-loader, url-loader 和 file-loader 的功能类似,但是 url-loader 可以指定在文件大小小于指定的限制时,返回 DataURL。
安装loader

npm install url-loader file-loader html-loader -D

最好两个loader都安装下。
修改下文件目录

webpack-demo
  |- package.json
  |- webpack.config.js
  |- /src
    |- icon.jpg
    |- index.less
    |- index.js
    |- index.html

src/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack</title>
</head>
<body>
  <div id="box1"></div>
  <div id="box2"></div>
  <div id="box3"></div>
  <img src="./icon.jpg" alt="">
</body>
</html>

src/index.less

#box1{
  width: 100px;
  height: 100px;
  background-image: url('./icon.jpg');
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

#box2{
  width: 200px;
  height: 200px;
  background-image: url('./icpn.png');
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

#box3{
  width: 300px;
  height: 300px;
  background-image: url('./icpn.jpg');
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

src/index.js

import './index.less';

webpack.config.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        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,
          name: '[hash:10].[ext]'
        }
      },
      {
        test: /\.html$/,
        // 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
        loader: 'html-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

执行npm run build即可在页面上看到对应的页面显示出来了。

6. 处理其他资源

在项目中处理html,js,css,less等资源以外还有字体资源。
webpack.config.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].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]',
          outpath: 'assets'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

执行npm run build即可将webp|svg|eot|ttf|woff|woff2等资源文件打包进dist文件夹。
当本地资源较多时,有时会希望它们能打包在一个文件夹下,只需要在 file-loader 的 options 中指定 outpath,如: outputPath: ‘assets’。在url-loader中也可以配置同样字段,这样我们可以将图片资源打包在同一文件下。

7. 清空dist文件

我们会发现在执行npm run build时,dist文件夹下的文件并不会自动删除,这时候就需要我们配置插件在每次打包的时候能够将之前的文件清空。我们需要插件: clean-webpack-plugin。
安装依赖:

npm install clean-webpack-plugin -D

以前,clean-webpack-plugin 是默认导出的,现在不是,所以引用的时候,需要注意一下。另外,现在构造函数接受的参数是一个对象,可缺省。

//webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    //...
    plugins: [
        //不需要传参数喔,它可以找到 outputPath
        new CleanWebpackPlugin() 
    ]
}

现在每次打包的时候都会将老的文件全部清空,这样就不会分不清新就打包文件了。

8. devServer

写了这么多我们还不能实时查看我们在页面中修改的内容,每次都需要打包完,在构建好的文件中打开html文件查看我们修改的东西。
需要实时查看修改的东西需要安装对应的依赖:

npm install webpack-dev-server -D

webpack.config.js

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:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
  // 特点:只会在内存中编译打包,不会有任何输出
  // 启动devServer指令为:npx webpack-dev-server
  devServer: {
    // 项目构建后路径
    contentBase: resolve(__dirname, 'build'),
    // 启动gzip压缩
    compress: true,
    // 端口号
    port: 3000,
    // 自动打开浏览器
    open: true
  }
}

npm scripts

"scripts": {
    "build": "webpack --config webpack.config.js",
    "start": "webpack-dev-server"
 }

执行npm start即可在localhost:3000中查看页面,当我们在index.js文件中增加一句console.log(‘Updating…’),在控制台中即可看到打印的内容。

以上内容是webpack的基础内容,但是还差的很多还有很多优化需要完善,后面会出关于webpack的进阶以及优化,敬请期待!

评论区

励志做一条安静的咸鱼,从此走上人生巅峰。

2

1

1

举报