webpack配置工程师(一):基本篇

240 阅读5分钟

简介

为自己了解webpack的过程做一个总结,也希望对想要了解的小伙伴有所帮助。

准备工作

既然是学习了解webpack,那我假定你了解npm和node.js了

核心概念

先对核心概念有个大概的了解,不理解也没关系,看完后面的例子应该会有一定的认识。

  • Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
  • Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开- 始递归找出所有依赖的模块。
  • Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
  • Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
  • Plugin:扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
  • Output:输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果。

环境准备

1.新建一个工程目录study_webpack(用于尝试各种例子) 2.全局安装webpack(为了方便用命令,安装的版本看下面的文件)

cnpm install -g webpack
cnpm install -g webpack-cli

tip:考虑到后续的一些插件的版本问题,放出我的package.json

{
  "name": "webpack-study-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {},
  "keywords": [],
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "css-loader": "^1.0.1",
    "html-webpack-plugin": "^3.2.0",
    "vue-loader": "^15.4.2",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^4.25.1",
    "webpack-cli": "^3.1.2"
  },
  "dependencies": {
    "vue": "^2.5.17"
  }
}

demo01(one entry)

基本栗子演示单个入口webpack打包结果,后续例子无特殊说明均采用该目录结构

在demo1目录下准备调用文件dist/index.html

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- 引入打包的文件 -->
    <script src="./bundle.js"></script>
</body>

</html>

入口文件index.js

document.write("<h1>Hello World</h1>");

webpack配置webpack.config.js

const path=require('path');

module.exports = {
    entry: "./index.js",
    output: {
        filename: "bundle.js",
        path:path.resolve(__dirname,"./")
    }
};

在终端中执行webpack命令(webpack.config.js所在的目录)

tip:webpack默认读取目录下的webpack.config.js的配置文件。

执行结果

Hash: 7a488a408fbb07bfacd8
Version: webpack 4.25.1
Time: 273ms
Built at: 2018-11-11 16:19:40
    Asset       Size  Chunks             Chunk Names
bundle.js  968 bytes       0  [emitted]  main
Entrypoint main = bundle.js
[0] ./index.js 40 bytes {0} [built]

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/concepts/mode/

第一个webpack的例子成功了,是不是很简单,马上就可以成为webpack配置工程师了,想想还有些小激动。

demo02(multiple entry)

往往一个应用不仅仅只有一个入口(第三方库啦,多个页面啦,等等)

在demo2目录下面写调用文件dist/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="./bundle1.js"></script>
    <script src="./bundle2.js"></script>
</body>
</html>

然后是入口文件module1.jsmodule2.js

document.write("<h1>Hello Module1</h1>");
document.write("<h1>Hello Module2</h1>");

打包结果执行结果

demo03(use loader)

Webpack 把一切文件看作模块,要支持非 JavaScript 类型的文件,需要使用 Webpack 的 Loader机制

target:编译.vue文件

准备工作:

cnpm i vue --save
cnpm i vue-loader --save-dev
cnpm i css-loader --save-dev
cnpm i vue-template-compiler --save-dev

新建demo03目录,调用文件dist/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
    <script src="./bundle.js"></script>
</body>
</html>

入口文件index.js

import Vue from "vue";
import App from "./index.vue";

/* eslint-disable no-new */
new Vue({
    el: "#app",
    template: "<App/>",
    components: { App }
});

index.vue文件

<template>
  <div id="app">
      {{msg}}
  </div>
</template>

<script>
export default {
    name: "app",
    data: function() {
        return {
            msg:"hello loader"
        };
    }
};
</script>

<style>
</style>

最后是配置文件webpack.config.js

const VueLoaderPlugin = require("vue-loader/lib/plugin");

module.exports={
    entry:"./index.js",
    output:{
        filename:"bundle.js"
    },
    resolve: {
        alias: {
            vue$: "vue/dist/vue.js" // 设置别名,找到node_modules下的vue
        },
        extensions: [".js", ".json",".vue"] // 支持.vue扩展
    },
    module:{
        rules:[
            {
                test:/\.vue$/,
                loader:"vue-loader" // 添加vue-loader
            }
        ]
    },
    plugins:[
        new VueLoaderPlugin() // vue-loader需要添加插件配置
    ]
}

相比前面的例子抛开其中的优化配置(别名之类的),实际上添加了一个module.rules选项,这个选项的作用专门用来配置loader,其中test字段通过正则匹配模块扩展名,告诉webpack对非javascript模块应用什么loader。

多个loader的例子容我省略,你(我)辣(偷)么(个)机(懒)智

demo04(use plugins)

Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性

所以,综上所述,plugins就是用来扩展webpack的,比如工作流(代码压缩),提高开发效率(热重载,静态服务器)等。

ps:其实上一个例子有plugins配置,不过那是vue-loader需要

target:动态生成html

前面的例子,我们的调用的html都是预先生成的,实际开发中几十个页面打包一次纯手动成本太高,我们以html-webpack-plugin插件为例

入口文件index.js

var name1="hello";
var name2="plugins";

document.write(`<h1>${name1} ${name2}</h1>`);

配置文件webpack.config.js

先安装插件

cnpm i html-webpack-plugin --save-dev
var HtmlWebpackPlugin = require("html-webpack-plugin");
var path = require("path");

module.exports = {
    entry: "./index.js",
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "bundle.js"
    },
    plugins: [new HtmlWebpackPlugin({ // 在插件数组里面加一个插件就好了,是不是so easy
        title:"demo04 title",
        template:"./template.html",
        inject:true
    })]
};

tip:该插件我们配置一个html模板

模板文件template.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
    
</body>
</html>

想想几十个页面通过一个模板生成是不是效率会高上不少呢

未完待续