从0开始的Webpack - 写Demo用的简单配置

前言

现在的前端,一定都用过Vue或者React,多多少少都有接触过webpack,我还清楚地记得第一次看Vue的Webpack配置时,仿佛在看天书通常。webpack做为前端工程化的核心知识之一,由于其功能太多,配置项又多又杂,初学时也比较难啃。css

这是一个面向初学者的webpack系列博文。从0开始,一步步搭建出完整的、适用于常规环境的webpack配置。html

每章都以树状结构扩深知识点,尽量的涵盖更多更深的知识内容,同时保留每一个章节的全部代码。前端

目录构建

首先建立一个文件,而后执行 npm initwebpack

随后建立对应子文件夹git

.webpackLemo // 文件夹
│
│-- config // 存放配置文件
│
│-- public // 存放模板
│
│-- src // 存放入口文件
│
└─- package.json
复制代码

写Demo用的简单配置

咱们有了基本文件夹,接下来开始构建最基本配置,能知足平时写demo用。github

支持打包

首先安装webpack工具库web

npm i webpack webpack-cli算法

建立入口文件npm

// src/index.js

console.log("Webpack Lemo");
复制代码
// public/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 Lemo</title>
</head>
<body>
    <script src="./main.js"></script> //打包后的文件为 main.js 在这里手动写入
</body>
</html>
复制代码

建立配置文件json

// config/webpack.config.js

const path = require('path');
module.exports = {
    entry: {
        main: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, '../build')
    }
}
复制代码

entry :入口起点配置。简单来讲,由html直接引用的文件称为入口起点,从这个起点开始,应用程序启动执行。例子中的 main 为入口起点的 [name] 值

output:输出配置。webpack打包完成,怎么输出,要输出哪些文件,输出到哪等相关信息的配置

output.path 要求接受一个绝对路径。 path.resolve 方法会把一个路径或路径片断的序列解析为一个绝对路径,__dirname 指向当前文件的路径

entry 配置里使用的是相对路径,这个路径默认指向代码被执行时路径,即 webpackLemo 文件夹的根目录。可经过设置 context 来修改路径上下文。

// 与正文中的配置效果等同
{
    context: path.resolve(__dirname),
	entry: {
        main: '../src/index.js'
    }
}
复制代码

关于entry的更多信息 关于output的更多信息

// package.json
{
  ...
  "scripts": {
    "dev": "webpack --config ./config/webpack.config.js"
  },
  ...
}
复制代码

接下来只需在命令行里执行 npm run dev 就能进行第一次打包

先忽视 warning ,能够看见webpack自动打包了 src 目录下的文件,在根目录下自动生成build文件,并将打包后的入口文件命名为 main.js 放入build文件中。

而后咱们能够把 public 目录下的 index.html 手动复制到 build 目录下。

完成以上操做后,咱们的目录会长成这样

.webpackLemo
│
│-- build // 存放打包后的文件
│  │-- main.js // src/index.js打包生成的文件
│  │-- index.html // 从public中手动复制
│
│-- config
│  │-- webpack.config.js // 新建webpack配置文件
│
│-- public
│  │-- index.html // 新建html模板文件
│
│-- src
│  │-- index.js // 新建入口文件
│
└─- package.json
复制代码

用浏览器打开 ./build/index.html,能够看见控制台里输出了 在 ./src/index.js 里写的 console.log信息

模板处理

若是每次打包,都须要咱们手动粘贴一次 index.html,那也太麻烦了。若是有一个哥们儿能 帮咱们自动复制index.html文件,而且在index.html中自动引入咱们打包后的文件 那就行了。

这个哥们儿叫作 html-webpack-plugin

执行安装 npm i html-webpack-plugin

而后修改文件

// public/index.html

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

<body>
	// <script src="./main.js"></script>  // 删除手动写入的 对main.js的引用
</body>
</html>
复制代码
// config/webpack.config.js

...
// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin'); 

module.exports = {
    ...
    output: {
        ...
        filename: '[name].bundle.js',  // 添加filename配置
    },
    plugins: [ // 注意是个数组
        new HtmlWebpackPlugin({  // 在plugin中使用 html-webpack-plugin
            template: './public/index.html' // 配置模板项地址
        }),
    ]
}
复制代码

plugins:配置webpack插件的地方

关于plugins的更多信息

filename 配置项中使用了[name],这里的[name]为输出的模块名。除了[name],webpack还提供了别的模板语法,可在这里找到全部信息 output.filename

如今咱们再执行 npm run dev 能够看见此次打包生成的文件名为main.bundle.js,而且 build 目录下的index.html 文件里自动引入了 main.bundle.js

完成以上操做后,咱们的目录会长成这样

.webpackLemo
│
│-- build 
│  │-- main.js // 第一次打包生成的文件
│  │-- main.bundle.js // 第二次打包生成的文件
│  │-- index.html // 使用 html-webpack-plugin 后生成的html文件
│
...
复制代码

文件清理

能够看见第二次打包时,咱们修改了输出配置,生成了新的文件,可是第一次打包的内容仍是被保留了下来。其实第一次打包的内容已经用不上了,有没有什么哥们儿能帮咱们自动删除不须要的内容?

有,这个哥们儿叫作 clean-webpack-plugin

执行安装 npm i clean-webpack-plugin

而后修改文件

// config/webpack.config.js

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

module.exports = {
    ...
    output: {
        path: path.resolve(__dirname, '../build'),
        filename: '[name].[contenthash].js', // 咱们再修改一次输出文件名
    },
    plugins: [
        ...
        new CleanWebpackPlugin(); // 使用 clean-webpack-plugin
    ]
}
复制代码

如今咱们第三次执行 npm run dev ,能够看见build目录下头两次生成的入口文件都被清除了,只保留了第三次生成的内容。

完成以上操做后,咱们的目录就长成这样

.webpackLemo
│
│-- build 
│  │-- main.417cd68a8235c5cd4f89.js // 第三次打包生成的文件
│  │-- index.html
│
...
复制代码

到目前为止,已经支持了基本功能打包,下一步来处理css样式和file文件

打包css和file文件

对css的支持

对css文件的处理有2种方式:

  1. 将css代码以 <style> 标签的形式嵌入 html 中

  2. 生成css文件,以 <link> 标签的形式在 html 中引入

这里咱们只讨论第一种形式,第二种会在 代码分割(卫星) 中介绍

咱们须要4个插件

  • style-loader (github) 将css代码以 <style> 标签的形式嵌入 html 中
  • css-loader (github) 解析经过模块化引入的css文件
  • postcss-loader (github) 提供预处理css的一些能力,拥有许多子插件,提供了许多能力
  • autoprefixer (github) postcss-loader的子插件,提供厂商前缀自动补全能力,如 -m-

loader和plugin的区别

// 官方文档原文
While loaders are used to transform certain types of modules, plugins can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables.

// 渣译
loader通常用来转换某些类型的modules,而插件能够用来执行更普遍的任务,例如对包的优化、资源管理、环境注入等

// 大白话
loader是一个转换器,将A文件进行编译成B文件,好比:将A.less转换为A.css,单纯的文件转换过程。
plugin是一个扩展器,丰富了webpack自己,针对是loader结束后,webpack打包的整个过程,它并不直接操做文件,而是基于事件机制工做,会监听webpack打包过程当中的某些节点,执行普遍的任务
复制代码

执行安装 npm i style-loader css-loader postcss-loader autoprefixer

而后修改文件

// ./config/webpack.config.js

...
module.exports = {
    ...
    module: { // 这里是对象
        rules: [ // 这里是数组
            { // 数组中的每一个具体配置
                test: /\.css$/, // 匹配 .css文件
                use: [ // 当匹配上 .css 文件后,会依次使用loader进行处理
                    'style-loader',
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require('autoprefixer')
                            ]
                        }
                    }
                ]
            }
        ]
    }
}
复制代码

module:各类模块应该如何处理,由module进行配置

关于module的更多信息

loader的处理顺序为从下到上。正文中loader处理顺序为:postcss-loader、css-loader、style-loader

// ./src/index.js
import './index.css'

...
复制代码
// ./src/index.css

body {
    width: 100%;
    height: 200px;
  	background-image: linear-gradient(to right, red , yellow);
}
复制代码
// ./package.json
{
    ...
    "browserslist": [
        "iOS >= 6",
        "Android >= 4",
        "IE >= 9"
    ]
}
复制代码

browserslist 用来配置 咱们的应用会在哪些平台、哪些浏览器和浏览器版本上使用。 autoprefixer 会读取该项值,用来以为须要添加哪些前缀,若是运行在最新的浏览器上,也许不会添加相应的前置信息

browserslist 默认值:> 0.5%, last 2 versions, Firefox ESR, not dead

关于browserslist的更多信息

如今执行 npm run dev ,build 目录里没有新增 .css文件,用浏览器打开 ./build/index.html 文件,能够看见背景有个渐变色,从控制台里能够看见样式代码以 <style> 标签的形式嵌入到了html中,而且自带了厂商前缀

完成以上操做后,咱们的目录就长成这样

.webpackLemo
│
│-- src 
│  │-- index.js
│  │-- index.css // 新增长的css代码
│
...
复制代码

对less的支持 (非必要)

less其实就是css的预处理器,一些代码里可能会用sass,可是原理相似,这里就用less举例

在上一节的基础上,额外安装一个 less-loader 处理less文件

执行安装 npm i less-loader

而后修改文件

// ./config/webpack.config.js

...
module.exports = {
    ...
    module: {
        rules: [
            ...
            {
                test: /\.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',  // 只增长一行less-loader 处理less文件
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require('autoprefixer')
                            ]
                        }
                    }
                ]
            }
        ]
    }
}
复制代码
// ./src/index.js

import './index.less' // 引入less文件

...
复制代码
// ./src/index.less

body {
    width: 100%;
    height: 200px;
  	background-image: linear-gradient(to right, red , yellow);
}
复制代码

执行 npm run dev ,获得的效果和处理css同样

完成以上操做后,咱们的目录就长成这样

.webpackLemo
│
│-- src 
│  │-- index.js
│  │-- index.css
│  │-- index.less
│
...
复制代码

对file文件的支持

其实只要是文件,均可以处理,这里用图片文件举例

可用2种 loader 进行处理

  • file-loader (github) 解析经过模块化引入的文件,在打包的时候会获取打包后的地址,并在代码中返回这个地址,使得文件能够被读取
  • url-loader (github) 做用同file-loader,可是能把文件压缩成base64的形式,通常用于图片

这两个loader做用比较相似,最大的区别在于 file-loader 会生成文件, url-loader 会把文件数据压缩成base64直接使用,不会生成文件。二者能一块儿使用,在某些场景下比使用单一loader效果更好,可参考 这篇博文(卫星)

这里我用file-loader举例

执行安装 npm i file-loader

而后修改文件

// ./config/webpack.config.js

...
module.exports = {
    ...
    module: {
        rules: [
            ...
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    'file-loader'
                ]
            }
        ]
    }
}
复制代码
// ./src/index.js

...
import img from '../statics/imgs/img.jpg'

const myimg = new Image();
myimg.src = img;
document.body.appendChild(myimg);
...
复制代码

执行 npm run dev ,能够看见build文件里增长了打包后的图片文件,打开 ./build/index.html 后也能看到相应的图片被挂载到页面上

完成以上操做后,咱们的目录就长成这样

.webpackLemo
│
│-- build 
│  │-- 051fa5032109fbc8005c856a48cf1c52.jpg
│  │-- index.html
│  │-- main.a14556a5d43741e69cdd.js
│
│-- statics // 存放静态资源
│  │-- imgs // 存放图片
│  │  │-- img.jpg
│
...
复制代码

到如今,咱们已经支持css打包和文件打包,本身写demo时,使用这样的webpack配置已经OK了,可是我每次改了代码都要从新执行一次 npm run dev ,真的太麻烦,若是能让webpack自动刷新页面就行了。

构建开发环境

让咱们来构建一个开发环境,让咱们每次更新的时候,webpack能自动帮咱们打包,而且能实时刷新页面.

要能实现实时刷新页面,webpack提供了3种能力

  1. webpack watch mode webpack 观察模式,最简单的方法,但功能所以也少了不少
  2. webpack-dev-server 相对简单的web server,而且具有live reloading(实时从新加载) 功能
  3. webpack-dev-middleware 最复杂的一种,须要本身写服务配置,但可塑性也最高

关于dev-server的更多信息

关于3种配置的更多信息

这里咱们采用 webpack-dev-server

执行安装 npm i webpack-dev-server

而后修改文件

// ./config/webpack.config.js

...
module.exports = {
    mode: 'development', // 设置mode为'development'模式
    devtool: 'cheap-module-eval-source-map', // 设置source-map
    devServer: {
        contentBase: './build',
        open: true
    },
    ...
}
复制代码

mode:至关于设置一套预设优化配置,默认为 none。详细可查看 官网文档

devtool:用于配置source-map,用来加强调试能力,不一样的值会影响构建和重构建的速度。 详细可查看 官方文档

// package.json

{
    ...
    "scripts": {
        // 把dev改为build
        "build": "webpack --config ./config/webpack.config.js",
        // 这里改为dev,并使用新命令项
        "dev": "webpack-dev-server --config ./config/webpack.config.js"
	},
	...
}
复制代码

接下来执行 npm run dev ,webpack帮咱们启动了一个端口号为8080的服务器,并自动打开了浏览器,咱们修改代码,能自动帮咱们打包新代码,并刷新页面。

总结

到这里,一个能打包、能处理css、处理文件、自启服务器、修改代码后能自动打包,自动刷新页面的配置就完成了。这样一个简单的配置已经实现我的写demo的需求,例如跑跑算法代码,测试一段代码的输出等等。

工具梳理

本章使用:

    • webpack、webpack-cli webpack工具库
    • webpack-dev-server webpack web-server
  1. loader

    • file-loader 解析经过模块化方式引入的文件,输出成文件
    • url-loader (非必要) 经过模块化方式引入的文件,以base64的形式输出
    • style-loader 将css代码以 <style> 标签的形式嵌入 html 中
    • css-loader 解析经过模块化引入的css文件
    • postcss-loader 提供预处理css的一些能力,拥有许多子插件,提供了许多能力
    • less-loader (非必要) 解析less代码文件
  2. plugins

    • clean-webpack-plugin 每次打包能清空打包文件夹里以前的内容
    • html-webpack-plugin 能自动生成Html文件,并自动引入打包生成的js文件
    • autoprefix postcss-loader的子插件,提供厂商前缀自动补全能力,如 -m-

文档梳理

尾声

本章节代码仓库代码仓库

本章节Github-blog: Github-blog

若是文中有错误/不足/须要改进/能够优化的地方,但愿能在评论里友善提出,做者看到后会在第一时间里处理

若是你喜欢这篇文章,👍点个赞再走吧,github的星星⭐是对做者持续创做的支持❤️️

相关文章
相关标签/搜索