从零开始学webpack:基础配置

1,353 阅读5分钟

webpack是什么

webpack是一个非常实用的静态模块打包工具,它通过递归的方式构建一个包含应用程序需要的所有模块的依赖图,然后将这些文件打包成一个或多个bundle输出

为什么要使用webpack

早期的开发中都是将各种静态文件(比如图片,CSS等)手动引入到html中,然后直接在浏览器中运行html文件;在这个时期,遇到大型项目时要么将所有的JS全部写在一个文件中,要么是引入多个脚本;前一种方式会导致代码混乱;后一种方式会导致HTTP请求过多;

随着前端技术的发展,开始使用模块化对代码进行分割,让代码能够复用且更方便维护,但浏览器对模块化的支持并不统一;

webpack最核心的功能就是解决模块之间的依赖问题,通过对webpack的简单配置即可完成代码转换,压缩,文件优化,模块加载及打包等功能

安装webpack

npm install webpack webpack-cli -D

核心概念

entry: 构建入口

entry用于告诉webpack应该使用哪个模块做为构建的开始;其默认值为./src/index.js

module.exports = {
    entry: './src/main.js'
}

output: 构建输出

output指定了webpack构建完成后的文件输出位置以及输出后的文件名等信息;

const path = require('path') // nodeJs内置的path模块
module.exports = {
    entry: './src/main.js',
    output: {
        filename: 'main.[hash].js', // 输出文件的文件名
        path: path.resolve(__dirname, 'dist')
        // path属性用于指定输出的文件路径,它必须接收绝对路径
        // path.resolve()方法用于将相对路径转换成绝对路径
    }
}

[hash]: [hash]用于解决静态文件缓存问题;静态文件内容更改而文件名不更改的情况下,可能会因为浏览器缓存问题而获取不到新的内容,通过hash可以让每一次打包的文件名不重复

mode: 配置模式

webpack会根据配置模式自动调用相应的内置优化项; 可选的配置模式有development, production, none, 默认值为production

配置模式可以在webpack的配置文件中显式的指定

module.exports = {
    mode: 'development'
}

在实际的项目开发中,更多的是通过脚本的方式执行CLI,通过CLI的参数传递

<!-- package.json -->
"scripts": {
    "build": "webpack --mode=production",
    "dev": "webpack-dev-server --mode=development"
}

loader: 模块代码转换器

loader用于对模块中的源代码进行转换,webpack本质上只能理解JavaScript和JSON文件,如果要解析其他代码就需要对代码进行转换,比如将typeScript代码转换成javascript代码;

常用的loader属性

  • test: 使用正则筛选出需要使用loader的文件
  • use: 转换时需要使用的loader,可以同时使用多个loader;通过对象的方式可以对loader进行个性化的配置
  • include: 指定loader必须要应用的文件夹
  • exclude: 指定loader需要排除不处理的文件夹

loader的执行顺序

loader的执行顺序是从下往上,从右往左;也就是说,在代码中越靠后的loader越先执行;在下面的例子中,css-loader比style-loader先执行

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

plugin

webpack的插件系统,通过插件可以扩展webpack的功能

基础配置

webpack解析时默认从webpack.config.js文件提取配置,所以将webpack的相关配置都写到这个文件中

<!-- webpack.config.js -->
const path = require('path')
module.exports = {
    entry: './main.js',
    output: {
        filename: 'index.js',
        path: path.resolve(_dirname, 'dist')
    }
}

以上就是一个最基础的webpack配置,以当前(webpack.config.js所在的目录)目录下的main.js为入口开始构建,输出到当前目录下的dist文件夹中;

配置HTML模板

在单页面应用开发中都需要使用一个html文件作为模板;html-webpack-plugin用于指定一个html文件作为模板,并以这个模板为基础引入打包后的js,css等文件,然后根据output的配置输出

安装

npm install html-webpack-plugin -D

配置

<!-- webpack.config.js -->
let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    // 省略其他代码s
    plugins: [
        new HtmlWebpackPlugin({
          template: './index.html',   // 指定模板文件路径
          filename: 'index.html',   // 指定打包后输出的模板文件名
          minify: {   // 指定模板压缩的规则
              removeAttributeQuotes: true,     // 删除属性的双引号
              collapseWhitespace: true,   // 折叠空行
          },
          hash: true // 添加hash戳,hash可以避免缓存问题
        })
    ]
}

在上面的配置中,指定了模板的路径(template)以及打包完成后输出的文件名称(filename), 同时指定了模板文件的压缩规则(minify), 为解决缓存问题添加了hash戳,输出的模板文件都会带上hash值;更多html-webpack-plugin的配置可以参考官方文档

本地开发服务配置

webpack-dev-server提供了一个本地的web开发服务和热更新的能力;通过这个本地server直接访问应用可以更好的开发和调试

安装

npm install webpack-dev-server -D

配置

module.exports = {
    devServer: {
        port: '8080',   // 开发服务端口
        host: 'localhost',
        progress: true, // 配置打包进度条
        contentBase: './dist',   // 指定静态服务的启动文件夹
    }
}

package.json文件中配置一个脚本,

<!-- package.json -->
"scripts": {
    "dev": "webpack-dev-server --mode=development"
}

此时通过npm run dev就可以启动一个本地开发服务了;更多关于webpack-dev-server的配置可以参考官方文档

webpack中css的配置

普通css的配置

webpack中css的解析主要依赖两个loader来完成:css-loaderstyle-loader

css-loader主要负责解析@import和url()
style-loader的主要作用是将css通过style标签的方式添加到模板文件中

安装

npm install style-loader css-loader -D

配置

<!-- webpack.config.js -->
module.exports = {
    // 省略其他代码
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
}

因为需要先解析css中的@import和url()语法,所以css-loader应该写style-loader之后

less和sass的配置

less和sass的解析依赖于less-loadersass-loader

使用这两个loader之前需要安装less和sass模块

安装

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

配置

<!-- webpack.config.js -->
module.exports = {
    // 省略其他代码
    module: {
        rules: [
            {
                test: /\.less/,
                use: ['style-loader', 'css-loader', 'less-loader']
            },
            {
                test: /\.scss/,
                use: [
                    'style-loader',
                    'css-loader',
                    {
                        loader: 'sass-loader',
                        options: {}
                    }
                ]
            }
        ]
    }
}

个性化loader配置: 在上面的配置中,scss-loader使用了对象语法进行配置,这种方式可以通过options对象来对loader进行更多个性化的配置

添加浏览器前缀

由于浏览器对css新属性的兼容性不统一,所以一些新的css属性在使用的时候需要为不同的浏览器加上前缀

autoprefixer通过postcss配置后可以为自动为css添加不同浏览器的前缀

安装

npm install autoprefixer postcss-loader -D

配置

<!-- webpack.config.js -->
module.exports = {
    // 省略其他代码
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','postcss-loader' 'css-loader']
            }
        ]
    }
}

接下来还需要通过postCSS配置autoprefixer才能自动添加前缀

 <!-- postcss.config.js -->
const autoprefixer = require('autoprefixer')
module.exports = {
    plugins: [autoprefixer]
}

提取css到单独文件中

通过前面的配置,已经可以解析css并且将css通过style标签的形式插入到模板中; 但是如果css内容过多,则会让模板文件中的css显得臃肿,这个时候就需要将css单独抽离出一个文件,以link的方式引入模板

mini-css-extract-plugin插件用于将CSS提取到单独的文件中

安装

npm install mini-css-extract-plugin -D

配置

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
    // 省略其他代码
     plugin: [
        new MiniCssExtractPlugin({
            filename: 'css/index.css'
        })
    ]
}

filename: 抽离之后的css文件名称,如果使用路径的方式则会将文件抽离到指定的路径下,以上面的代码为例,index.css会抽离到./dist/css/index.css

使用mini-css-extract-plugin插件之后,css将会抽离成单独的文件,所以需要使用MiniCssExtractPlugin.loader替换原有的style-loader

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
    // 省略其他代码
     plugin: [
        new MiniCssExtractPlugin({
            filename: 'index.css'  // 抽离后的css文件名
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    }
}

webpack中JS的配置

由于浏览器对新的ES语法支持并不是一致,为了保证代码的兼容性,需要将新的ES语法(ES6,ES7,ES8等)转换为浏览器都支持ES5语法;在webpack中,这个转换的功能主要通过babel来完成

安装

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

配置

module.exports = {
    // 省略其他代码
    module: {
        rules: [
            {
                test: '/\.js$/', 
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            '@babel/preset-env'
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'),  // 希望应用的文件夹
                exclude: /node_modules/ // 需要排除的文件夹
            }
        ]
    }
}

文件压缩

webpack中的文件压缩通过配置optimization来完成

module.exports = {
    // 省略其他代码
    optimization: [
    
    ]
}

css文件压缩

optimize-css-assets-webpack-plugin插件可以用于css文件的压缩

安装

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

配置

const OptimizeCss = require('optimize-css-assets-webpack-plugin')
module.exports = {
    // 省略其他代码
    optimization: [
        new OptimizeCss()
    ]
}

js文件压缩

uglifyjs-webpack-plugin插件用于JS文件的压缩

安装

npm install uglifyjs-webpack-plugin -D

配置

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
    // 省略其他代码
    optimization: [
        new UglifyJsPlugin({
            parallel: true
        })
    ]
}

图片的配置

webpack中的图片配置可以使用url-loader来完成,url-loader与file-loader功能相似;但是它可以在图片大小低于指定的限制时,将图片转换为base64格式,以此减少HTTP请求

安装

npm install url-loader -D

配置

module.exports = {
    // 省略其他代码
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10240,   // 单位为字节
                            outputPath: 'img/'
                        }
                    }
                ]
            }
        ]
    }
}

outputPath: 指定图片输出路径,已上面的配置为例,图片文件将输出到./dist/img/目录下

全局变量的配置(以jquery为例)

当下前端开发的主流框架都是以数据驱动的,很少去操作DOM;但是如果项目业务特殊需要用到jQuery的话,为了避免每一次使用的时候都通过import去引入,可以使用webpack配置一个全局变量

webpack全局变量的配置主要使用webpack的内置模块(内置模块不需要通过npm安装,直接使用即可)ProvidePlugin来完成,详细内容可以参考官方文档

配置

npm install jquery
module.exports = {
    // 省略其他代码
    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery"
        })
    ]
}

打包清空输出目录

为了避免多次打包后输出目录混乱(举例:每次打包都输出一个名称带hash的文件,多次打包后就会产生多个文件在同一个目录中,但是只有最后一次输出的文件才有用)的问题,可以通过clean-webpack-plugin插件,在每一次打包的时候都将输出目录清空,这样,每一次打包后的输出文件夹中都会比较干净

安装

npm install clean-webpack-plugin -D

配置

const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
    // 省略其他代码
    plugins: [
        new CleanWebpackPlugin()
    ]
}

写在最后

本文主要了解了webpack中的一些核心概念并介绍了一些常用配置所需要的插件,loader等,通过这些配置就已经可以满足多数场景的基本开发需求了

本文所对应的配置源码已提交到我的github

更加个性化的配置可以参考进阶配置

end