webpack 入门教程&配置

1,281 阅读4分钟

什么是Webpack?

webpack 是一个JavaScript程序静态模块打包工具,当webpack处理程序时,会递归构建一个依赖关系图,对程序需要的每个模块进行编译、压缩、打包等,可打包成一个文件或多个文件。

webpack 的核心概念

其中 entry、output、loader和plugins 是 webpack 的四个核心概念

  • entry(入口)
  • output(输出)
  • loader
  • plugins(插件)
  • mode(模式)
  • module(模块)
  • chunk

1. entry

入口起点,是指在 webpack 中应该使用哪个模块,来作为构建内部依赖的开始,webpack 会找出哪些模块是根据入口起点的文件依赖的。

每个依赖的模块经过处理后,最终都将打包到名叫 buildle 文件中。

webpack中设置entry属性指定一个入口起点或多个入口起点。

webpack.config.js

module.exports = {
    entry: "./src/index.js"
}

2. output

output属性是告诉 webpack 在哪里输出我们创建的 buildle 文件,以及如何命名这些文件和设置这些文件的所在路径。

webpack.config.js

let path = reuqire("path");
module.exports = {
    outpur:{
        path:path.resolve(__dirname,"dist"),
        filename:"build.js"
    }
}

output.pathoutput.filename 分别指定输出文件的路径,和输出文件的名称

3. loader

lodaer 可以理解为模块转换器,loader 可以将所有模块内容转为所需的内容,然后在利用 webpack 打包功能,对他们进行处理。

webpack.config.js

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

module对象中的rules属性必须有包含testuse属性,这将告诉 webpack 在以.css结尾的文件打包时,先使用css-loader对他进行转换。

4. plugins

loader 被用于转换模块,而 plugins 用于更加广泛的范围,webpack 提供了丰富的插件解决,基于这些接口我们可以做到任何想做的事情。

webpack.config.js

let webpack = require("webpack"); //适用于 webpack 提供的内部插件
let HtmlWebpackPlugin = require("html-webpack-plugin"); //外部插件,基于 npm 安装
module.exports = {
    plugins:[
        new HtmlWebpackPlugin() //使用插件
    ]
}

5. mode

可选择development(开发模式)和production(生产模式)中一个来设置mode的值。 webpack.config.js

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

6. module

在 webpack 中一切皆是模块,每一个模块都对应一个文件,webpack 会从 entry 开始递归找出所有依赖的模块。

7. chunk

代码块,一个 chunk 由多个模块组成,用于代码的分割与合并。

配置 webpack

webpack 的配置文件叫做webpack.config.js。是一个导出对象javascript文件。

webpack 配置是标准的Node.js CommonJS模块。在 webpack 配置文件中,采用require导入文件。

1. 初始化

1.1 创建 & 初始化项目

mkdir webpack-demo && cd webpack-demo && npm init -y

1.2 安装 webpack, D 是局部安装

npm install webpack webpack-cli -D

1.3创建 src 和 dist 目标

mkdir src && mkdir dist

创建 src 目录下的index.js

touch index.js

2 配置 webpack

2.1 配置webpack 文件

mkdir webpack.config.js

2.2 配置 webpack.config.js

let path = path.require("path");
module.exports = {
    entry:"./src/index.js",
    output:{
        path:path.resolve(__dirname,"dist"),
        filename:"build.js"
    }
}

entry 属性的配置可以是多个入口

cd src && mkdir b.js
module.exports = {
    entry:{
        A:"./src/index.js",
        B:"./src/b.js"
    },
    output:{
        path:path.resolve(__dirname,"dist"),
        filename:"[name]"
    }
}

多个入口的情况下,output.filename属性值改为"[name]",这样输出的文件名和entry设置的入口文件名一一对应。

2.3 在 src 目录创建 index.html 文件

touch index.html

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> 世界,你好</div>
</body>
</html>

2.4 配置 package.json 文件,可以使我们在命令行使用npm run build

"scripts":{
    "build":"webpack"
}

2.5 配置mode
webpack 的 mode 配置用于提供配置选项告诉 webpack 相应的使用其内置的优化,mode 有三个值:developmentproductionnone

{
    module.exports = {
        mode: "development"
    }
}

3 配置开发服务器

3.1 安装依赖

npm install webpack-dev-server -D

3.2 配置 package.json 文件,便于我们在命令行输入npm run dev

"scripts":{
    "dev": "webpack-dev-server"
}

3.3 配置webpack.config.js文件

    let path = require("path");
    
    module.exports = {
        devServer:{
            contentBase: path.resolve(__dirname,"dist"),
            host:"localhost",
            port:"3000",
            compress:true, // 是否 gzip 压缩
            open: true // 是否自动打开浏览器窗口
        }
    }

4 支持加载 css 文件

  • css-loader
  • style-loader

4.1 安装 loader

npm install css-loader style-loader -D

loader 执行顺序是从右到左,从上到下

4.2 配置webpack.config.js文件

    module.exports = {
        module:{
            rules:[
                {
                    test:/\.css$/,
                    use:["style-loader","css-loader"] // use属性值可以是 []、string和对象
                }
            ]
        }
    }

4.3 配置html-webpack-plugin插件并导入到webpack.config.js文件
html-webpack-plugin 简化了 HTML 文件的创建,并且能够自动产出一个 HTML 文件,并且在里面引入产出后的资源。详情请移步 npmjs 了解。

npm install html-webpack-plugin -D
let HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    plugins: [
        // 如果有多个 HTML 文件 HtmlWebpackPlugin 执行多次
        new HtmlWebpackPlugin({
            template: "./src/index.html", // 模板的文件路径
            filename:"main.html", // 将要写入在 HTML 中的文件名,默认是index.html
            chunks:["A"],
            hash:true, // 在产出的资源后面添加哈希值,以避免缓存
            minify:true, //是否对HTML压缩,默认是true
        })
    ]
}

5 css 分离

因为 css 的下载和 js 可以一起运行,所以当一个 HTMl 很大时,我们可以把 css 分离单独的文件。

5.1 安装依赖模块

npm install mini-css-extract-plugin -D

这个插件可以 css 提取到单独是文件中。支持按需加载 css 和 SourceMaps。此插件在 webpack 4上使用。

5.2 配置webpack-config.js文件

    let MiniCssExtractPlugin = require("mini-css-extract-plugin");
    
    module.exports = {
        module:{
            rules:[
                {
                    test:/\.css$/,
                    use:[MiniCssExtractPlugin.loader,"css-loader"] 
                    //该插件自带一个loader 用来处理css变成css文件形式的
                }
            ]
        },
        plugins:[
            new MiniCssExtractPlugin({
                filename:"style.css"//css 文件名
            })
        ]
    }

5.3 压缩 JS 和 CSS

因为使用了 css 分离的插件mini-css-extract-plugin,所以这时代码不在自动压缩,需要我们手动压缩代码。

5.3.1 压缩 CSS

安装依赖

npm install optimize-css-assets-webpack-plugin -D

配置webpack.config.js文件

let OptimizeCss = require("optimize-css-assets-webpack-plugin");
module.exports = {
    plugins: [
        new OptimizeCss()
    ]
}

5.3.2 压缩 JS

安装依赖

npm install uglifyjs-webpack-plugin -D

配置webpack.config.js文件

let UglijsWebpackPligin = require("uglifyjs-webpack-plugin");
module.exports = {
    plugins:[
        new UglijsWebpackPligin({
            cache: true,
            parallel: true,// 并行,多进程快速构建打包
            sourceMap: true // 映射代码源
        })
    ]
}

除了uglifyjs-webpack-plugin之外也可以使用terser-webpack-plugin

5.4 less 和 sass

安装依赖

npm install less less-loader -D
npm install node-sass sass-loader -D

配置webpack.config.js文件

let path = require("path");
let MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
    module:{
        rules:[
            {
                test:/\.less$/,
                exclude:/node_modules/, // 排除 node_modules 
                include: path.resolve(__dirname,"src"), // 选中范围
                use:[MiniCssExtractPlugin.loader,"css-loader","less-loader"]
            },
            {
                test:/\.scss$/,
                exclude:/node_modules/,
                include: path.resolve(__dirname,"src"), 
                use:[MiniCssExtractPlugin.loader,"css-loader","sass-loader"]
            }
        ]
    }
}

5.5 添加 CSS3 属性前缀

有时候为了处理兼容性问题,我们需要在 css 中加入-webkit,-ms,-o,-moz 这些前缀。

  • Trident内核:主要代表为IE浏览器, 前缀为-ms
  • Gecko内核:主要代表为Firefox, 前缀为-moz
  • Presto内核:主要代表为Opera, 前缀为-o
  • Webkit内核:产要代表为Chrome和Safari, 前缀为-webkit

安装依赖

npm install postcss-loader autoprefixer -D

配置webpack.config.js文件

module.exports = {
    module:{
        rules:[
            {
                test:/\.scss$/,
                exclude:/node_modules/,
                use:[MiniCssExtractPlugin.loader,"css-loader","postcss-loader","sass-loader"]
            }
        ]
    }
}

还需要新建一个postcss.config.js配置文件并配置

touch postcss.config.js
module.exports = {
    plugins:[
        require("autoprefixer")
    ]
}

6 支持图片

引入图片的三种方式

  • js
  • css
  • html

6.1 安装依赖

npm install file-loader url-loader -D

6.2 配置webpack.config.js文件

module.exports = {
    module:{
        rules:[
            {
                test:/\.(png|jpe?g|fig)/,
                use:{
                    loader:"url-loader",
                    options:{
                        limit:200*2024
                    }
                }
            }
        ]
    }
}

file-loaderurl-loader的区别是url-loaderlimit属性可设置一个参数。
limit 值在限制大小之内采用 base64,超过采用file-loader

6.3 安装 HTML 中可用图片依赖

npm install html-withing-loader -D

配置webpack.config.js文件

module.exports = {
    module: {
        rules:[
            {
                test:/\.html$/,
                loader: "html-withing-loader"
            }
        ]
    }
}

7 转义 ES6/7/JSX

Babel是一个可以编译 JavaScript 的平台,能够把 ES6/7/JSX 编译成 ES5。

7.1 安装依赖

npm install babel-loader @babel/core @babel/preset-env -D

7.2 配置webpack.config.js文件

modules.exports = {
    module:{
        rules:[
            {
                test:/\.js$/,
                exclude:/node_modules/,
                use:{
                    loader: "babel-loader",
                    options: {
                        presets: ["@label/preset-env"], // ES6 转成ES5 模块
                    }
                }
            }
        ]
    }
}

此外,还有分别转换装饰器和类的babel包@babel/plugin-proposal-decorators&@babel/plugin-proposal-class-properties

7.3 @babel/plugin-transform-runtime 插件 从 ES6 编译 ES5 的过程中,有一些是不被应用的。例如

index.js添加 Generator 函数

function *fn(){
    yield "哈哈哈..."
}
console.log(fn().next());

会在浏览器控制台报错,提示regeneratorRuntime方法找不到。因为此时在编译后的 js 文件中,没有regeneratorRuntime的由来,只有使用。

index.js:8 Uncaught ReferenceError: regeneratorRuntime is not defined

@babel/plugin-transform-runtime 就是起到帮助代码填充在转义过程中一些不存在的代码。该插件在使用时,还需依赖@babel/runtime

7.4 安装依赖

npm install @babel/plugin-transform-runtime @babel/runtime -D

7.5 配置webpack.config.js文件

module.exprots = {
    module:{
        rules:[
            {
                test:/\.js$/,
                exclude:/node_modules/,
                use:[{
                    loader:"babel-loader",
                    options:{
                        presets:["@babel/preset-env"],
                        plugins:["@babel/plugin-transform-runtime"]
                    }
                }]
            }
        ]
    }
}

7.6 @babel/polyfill 插件

因为@babel/plugin-transform-runtime并不能解决类似"foobar".includes("foo")实例上的这种问题。如果需要polyfill可使用@babel/polyfill

安装依赖

npm install @babel/polyfill -D

修改index.js文件,可直接在文件里导入@babel/polyfill使用

import "@babel/polyfill";
'aaa'.includes('a');

8 调式代码

sourcemap是帮助我们解决开发代码和实际运行不一致时帮助我们debug到原始代码 8.1 配置webpack.config.js

module.exports={
    devtool: "source-map" // 代码映射,可直接找到源代码的行列位置
}

source-map会单独打包成一个.map的文件和原始代码相关联。cheap-module-eval-source-map 则不会打包.map文件,而是直接在打包文件的内部进行相关联,不能准确的定位到列数。有关其他详细参数可到 webpack

9 监听打包

webpack 可以监听文件变化,当修改文件内容后会重新编译。启动watch模式,意味着在构建之后, webpack 将继续监听任何文件的更改。watchOpions可以配置一些监听打包规则 9.1 配置webpack.config.js

module.exports={
    watch:true,
    watchOpions:{ // 监听打包配置选项
        poll:1000, // 以秒为单位,每1秒检查检查一次
        ignored:{ // 排除 node_modules 文件夹
            test:/node_modules/
        }
    }
}

10 打包前清除打包目录

10.1 安装依赖

npm install clean-wbpack-plugin

10.2 配置webpack.config.js

let CleanWebpackPlugin = require("clean-webpack-plugin");
module.exports={
    plugins:[
        new CleanWebpackPlugin({
            cleanOnceBeforeBuildPatterns:["./dist"]
        })
    ]
}

11 复制文件

11.1 安装依赖

npm install copy-webpack-plugin

11.2 配置webpack.config.js

let CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports ={
    plugins:[
        new CopyWebpackPlugin([
            {from:"./src/test.js",to:path.resolve(__dirname,"dist")}
        ])
    ]
}

11.3 目录展示

12 为打包文件添加注释

BannerPlugin是 webpack 自带的一个插件,能够给打包后的文件添加一些注释之类的信息。

12.1 配置webpack.config.js

let webpack = require("webpack");
module.exports = {
    plugins:[
        new webpack.BannerPlugin("你好")
    ]
}

12.2 展示

13 解析第三方文件

想在 js 文件中引入一个style.css,写的时候想忽略.css格式或者忘记写的时候,那么解析就会报错。因为默认这样引入import style的是一个 js 文件,而不是我们想要的 css 文件。resolve`属性可以帮助我们的解决这个问题。

13.1 配置webpack.config.js

let path = require("path");
module.exports={
    resolve:{
        modules:[path.resolve("node_modules")],// 指定搜索目录,可以是多个目录。在引入的外部 css 文件,node_modeuls 找不到则会继续往上找到
        ailas:{ // 起个别名
            "style":"./src/style.css"
        },
        extensions:[".js",".json",".css"] // 自动解析设置的扩展名,默认 .js .json
    }
}

14 服务器代理

希望前后端在同一个域名下发送 API 请求时,那么代理某些 URL 是很有必要的

14.1 配置一个server文件 安装依赖

npm install express -D
let express = require("express");
let app = express();
app.get("/api/user",async (req,res)=>{
    res.json({name: "哈哈"})
})
app.listen(3000)

14.2 配置webpack.config.js

module.exports={
     devServer:{
        proxy:{
            "/api":"http://localhost:3000"
        }
    },
}

14.3 自己 mock 数据

配置webpack.config.js

module.exports={
    devServer:{ // 可以自己造假数据
        before(app){// 默认 webpack-dev-server 启动的时候会调用这样的一个钩子函数,app 是我们的 express()
            app.get('/api/user',(req,res)=>{
                res.json({name:"xm"})
            })
        }
    },
}

15 分离代码块

weboack 3 还需要commonChunklsPligin插件,在webpack 4就没有了,这里以 4 为准

module.exports={
    optimization:{
        splitChunks:{ //分离代码模块
            cacheGroups:{ // 缓存组
                common:{
                    chunks:"initial",
                    minSize:0, // 只要公用的部分超过0个字节 就抽离出来
                    minChunks:2 // 至少引用2次才抽离
                },
                vendor:{ //抽离第三方插件的
                    priority:1, // 权重 先执行,为了避免在 common 这里把所有的文件都抽离出来 默认是0
                    test:/node_modules/,
                    chunks:"initial",
                    minSize:0,
                    minChunks:2
                }
            }
        }
    }
}

16 热更新

react-hot-loader只更新修改的部分

16.1 安装依赖

npm install react-hot-loader

16.2 配置.babelrc

{
    "plugins":["react-hot-loader/babel"]
}

配置webpack.config.js

module.exports={
    module:{
        rules:[
            {
                test:/\.js$/,
                use:[{
                    loader:"babel-loader",
                    options:{
                        presets:["@babel/preset-env","@babel/preset-react"] // 预设react
                    }
                }]
            },
            {
                test:/\.css$/,
                loader:["style-loader","css-loader"]
            }
        ]
    },
}

16.3 修改文件

home.js

import * as React from "react";
import 'react-hot-loader';
import { hot } from 'react-hot-loader/root';
class App extends React.Component{
    render(){
        return <div>Hello111 World!<input type="text"/></div>;
    }
}
export default hot(App);

修改 index.js

import * as React from "react";
import * as ReactDOM from "react-dom";
import App from "./home";
ReactDOM.render(<App/>, document.getElementById('root'));

基本的配置到此就结束了。

有任何问题欢迎指出。有其他详情请移步npm & babel & 中文webpack官网

都看到这里给点个赞呗 ^_^ ~