React项目中webpack的配置过程

初始化一个web项目
使用npm init -y 初始化一个项目
在项目目录下创建src, dist文件夹,创建webpack.config.js配置文件
然后在src文件夹下创建index.js, index.html文件

复制代码
然后安装依赖包
npm i jquery -S 安装jQuery包
npm i webpack webpack-cli webpack-dev-server html-webpack-plugin -D 安装开发调试包
安装loader调试工具
yarn add style-loader css-loader sass-loader node-sass url-loader file-loader  --dev
安装babel预编译工具, babel-loader@7需要添加版本号,否则可能导致babel-loader与babel-core版本不兼容问题
yarn add babel-loader@7 babel-core babel-plugin-transform-runtime babel-preset-env babel-preset-stage-0 babel-preset-react  --dev
安装项目工具和UI库
yarn add react react-dom  react-router-dom@4.2.2 antd@5.10.1

编写index.js脚本文件

复制代码
import $ from 'jquery'

$(function () {
    $('li:odd').css('backgroundColor','pink')
    $('li:even').css('backgroundColor','lightblue')
})

在index.html中导入index.js脚本文件

复制代码
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./index.js"></script>
</head>

编写webpack.config.js配置文件

复制代码
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    mode: 'development',
    //项目的入口与出口设置
    entry: path.join(__dirname, './src/index.js'),
    output: {
        path: path.join(__dirname, './dist'),
        filename: 'bundle.js'
    },
    plugins: [ //插件
        //在内存中生成一个页面,默认在项目的根目录下的内存中
        new htmlWebpackPlugin({
            //页面模板
            template: path.join(__dirname, './src/index.html'),
            filename: 'index.html'
        })
    ]
}

在package.json项目配置中添加短命令

复制代码
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    // --cacheBase: 指定托管目录, 如果没指定默认在项目内存的根目录下
    "dev": "webpack-dev-server --open --port 3000 --hot"
  },

执行npm run dev 进行打包调试
添加调试工具
添加loader加载器和babel预编译工具

添加loader加载器,让webpack处理js模块外的其他模块。
webpack默认只能打包处理以.js结尾的模块。其他非.js后缀名结尾的模块,webpack默认是不处理的。
需要调用loader加载器才可以正常打包,loader加载器的作用:协作webpack打包处理约定的文件模块。比如:css-loader: 可以打包处理.css相关的文件。

复制代码
使用scss设置css样式,需要使用css-loader解析器进行解析
npm i style-loader css-loader sass-loader node-sass url-loader file-loader -D
js中es6高级语法解析
npm i babel-core babel-loader babel-plugin-transform-runtime babel-preset-env babel-preset-stage-0 -D
在webpack.config.js中添加loader加载器配置
    module: {
        rules: [
            { test: /\.css$/, use:['style-loader', 'css-loader'] },
            { test: /\.scss$/, use:['style-loader', 'css-loader', 'sass-loader'] },
            { test: /\.(png|gif|bmp|jpg)$/, use: 'url-loader?limit=500000' },
            { test: /\.js$/, use:'babel-loader', exclude: /node_modules/ },
        ]
    }

开发完成,打包发布
新建发布配置文件webpack.pub.config.js
修改它的产物名称配置文件

复制代码
module: {
    rules: [
        { test: /\.css$/, use:['style-loader', 'css-loader'] },
        { test: /\.scss$/, use:['style-loader', 'css-loader', 'sass-loader'] },
        { test: /\.(png|gif|bmp|jpg)$/, use: 'url-loader?limit=5000&name=[hash:8]-[name].[ext]' },
        { test: /\.js$/, use:'babel-loader', exclude: /node_modules/ },
    ]
}

在package.json配置文件中,添加短命令pub,并在webpack命令中添加使用的配置文件名参数

复制代码
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "--cacheBase": "指定托管目录, 如果没指定默认在项目内存的根目录下",
    "dev": "webpack-dev-server --open --port 3000 --hot",
    "pub": "webpack --config webpack.pub.config.js"
  },

调用指令npm run pub, 打包出资源bundle.js, 图片, index.html。

复制代码
zhoufeideMacBook-Pro-2:webpack zhoufei$ npm run pub

> webpack@1.0.0 pub
> webpack --config webpack.pub.config.js

assets by path *.jpg 61.5 KiB
  asset 56e2b290-phone1.jpg 61.5 KiB [emitted] [immutable] [from: src/images/phone1.jpg] (auxiliary name: main)
  asset 7a417220207de157cf21.jpg 63 bytes [emitted] [immutable] [from: src/images/phone1.jpg] (auxiliary name: main)
asset bundle.js 344 KiB [emitted] (name: main)
asset index.html 660 bytes [emitted]

webpack编译器优化
1.产物图片优化
把项目中的所有图片在产物中放到一个images文件夹下面
通过修改webpack.pub.config.js中的module.rules项

复制代码
{ test: /\.(png|gif|bmp|jpg)$/, use: 'url-loader?limit=5000&name=images/[hash:8]-[name].[ext]' },

2.产物目录dist重建优化
每次生成产物时,都对dist目录进行先清理,再生成

复制代码
npm i clean-webpack-plugin -D

webpack.pub.config.js中进行配置清理插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

plugins: [ //插件
    /*
        每次构建产物都要重新创建dist目录保存产物
    */
    new CleanWebpackPlugin({cleanAfterEveryBuildPatterns:['dist']})
],

3.抽离第三方包
发布思路:bundle.js中只存放自己的代码,第三方包的代码都抽离到另外的JS包中
webpack@4以后的版本,弃用了许多@3的插件,其中包括:

复制代码
分离打包js文件的插件 webpack.optimize.CommonChunkPlugin();
压缩js文件的插件 webpack.optimize.UglifyJsPlugin();
定义产品上线环境webpack.optimize.DedupePlugun();
分离css文件插件extract-text-webpack-plugin();
css文件压缩插件 CssMinimizerPlugin();

webpack3的抽离方法

复制代码
在webpack.pub.config.js中修改entry的设置为如下:
//app和vendors的key名称都是自己自定义的,随便取的
entry: {
    app: path.join(__dirname, './src/index.js'),
    vendors: ['jquery'] //把要抽离的第三方包放到这个数组中
}, 

在pulgins的数组中添加抽离设置
new webpack.optimize.CommonsChunkPlugin({
    name: 'vendors', //指定抽离的入口
    filename: 'vendors.js' //抽离的所有第三方包的结果包名称。
})


然后将js文件放到一个统一的目录下:
output: {
    path: path.join(__dirname, './dist'),
    filename: 'js/bundle.js'
},

4.压缩js代码
在webpack.pub.config.js中的 plugins项目下,添加下面的js优化代码

复制代码
js代码压缩优化
new webpack.optimize.UglifyJsPlugin({
    compress: { //配置压缩项
        warnings: false //移除警告
    }
}),
new webpack.optimize.DedupePlugin({
    'process.env.NODE_ENV': '"production"'
})

5.压缩html代码

复制代码
在htmlWebpackPlugin模板中添加html优化配置
new htmlWebpackPlugin({
    //页面模板
    template: path.join(__dirname, './src/index.html'),
    filename: 'index.html',
    minify: {
        collapseWhitespace: true, //合并多余的空格
        removeComments: true, // 移除注释
        removeAttributeQuotes: true //移除属性上的双引号
    }
}),

6.从bundle.js中抽离css单独存放

复制代码
yarn add extract-text-webpack-plugin --dev
修改webpack.pub.config.js文件

const ExtractTextPlugin = require('extract-text-webpack-plugin')
添加插件
plugins: [ //插件

    //配置提取出来的css名称
    new ExtractTextPlugin({
        filename: 'style/[name].min.css' 
    })
],
修改css-loader的rules
module: {
    rules: [
        { test: /\.css$/, use: ExtractTextPlugin.extract({
            fallback: 'style-loader',
            use: 'css-loader',
            publicPath: '../' //指定抽离的时候,自动为我们使用的路径加上 ../前缀
        }) },
        { test: /\.scss$/, use: ExtractTextPlugin.extract({
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader'],
            publicPath: '../' //指定抽离的时候,自动为我们使用的路径加上 ../前缀
        }) },
    ]
}

7.压缩css

复制代码
yarn add optimize-css-assets-webpack-plugin --dev
修改webpack.pub.config.js文件

// 压缩css插件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

plugins: [ //插件
    /*
        压缩css
    */
    new OptimizeCssAssetsPlugin()
],

webpack项目模板
dev的webpack开发模板

复制代码
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
const { name } = require('file-loader')

module.exports = {
    mode: 'development',
    //项目的入口与出口设置
    entry: path.join(__dirname, './src/index.js'),
    output: {
        path: path.join(__dirname, './dist'),
        filename: 'bundle.js'
    },
    plugins: [ //插件
        //在内存中生成一个页面,默认在项目的根目录下的内存中
        /*
            html-webpack-plugin的作用有2个:
            1.自动将./src/index.html页面复制一份到项目根目录,放到了内存中。
            2.在内存中自动生成的index.html页面里,自动注入webpack打包的存在于内存中的bundle.js文件
        */
        new htmlWebpackPlugin({
            //页面模板
            template: path.join(__dirname, './src/index.html'),
            filename: 'index.html'
        })
    ],
    /*
        webpack默认只能打包处理以.js结尾的模块。其他非.js后缀名结尾的模块,webpack默认是不处理的。
        需要调用loader加载器才可以正常打包,loader加载器的作用:协作webpack打包处理约定的文件模块。比如:css-loader: 可以打包处理.css相关的文件。
    */
    module: {
        rules: [
            { test: /\.css$/, use:['style-loader', 'css-loader'] },
            //声明css模块化,使用CSS模块化解决多个css的作用域都是全局作用域,导致结果互相覆盖的情况
            //一般第三方库的样式文件是以css结尾的,所以不能直接对css开启模块化,会影响其他第三方库的展示,这里只对scss进行开启模块化
            // { test: /\.css$/, use:['style-loader', {
            //     loader: 'css-loader',
            //     options: {
            //         importLoaders: 1,
            //         modules: true,
            //         //自定义css模块化后的class名称
            //         // localIdentName: [name]-[local]-[hash:5]
            //     }
            // }] },
            { test: /\.scss$/, use:['style-loader', {
                loader: 'css-loader',
                options: {
                    importLoaders: 1,
                    modules: true,
                    //自定义css模块化后的class名称
                    // localIdentName: [name]-[local]-[hash:5]
                }
            }, 'sass-loader'] },
            { test: /\.(png|gif|bmp|jpg)$/, use: 'url-loader?limit=500000' },
            { test: /\.jsx?$/, use:'babel-loader', exclude: /node_modules/ },
        ]
    }
}

pub的webpack发布模板

复制代码
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
//导入每次删除文件夹的插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpack = require('webpack')
// 抽取Css插件
const ExtractTextPlugin = require('extract-text-webpack-plugin')
// 压缩css插件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
    mode: 'production',
    //项目的入口与出口设置
    entry: path.join(__dirname, './src/index.js'),
    //app和vendors的key名称都是自己自定义的,随便取的
    // entry: {
    //     app: path.join(__dirname, './src/index.js'),
    //     vendors: ['jquery'] //把要抽离的第三方包放到这个数组中
    // }, 
    output: {
        path: path.join(__dirname, './dist'),
        filename: 'js/bundle.js'
    },
    plugins: [ //插件
        //在内存中生成一个页面,默认在项目的根目录下的内存中
        /*
            html-webpack-plugin的作用有2个:
            1.自动将./src/index.html页面复制一份到项目根目录,放到了内存中。
            2.在内存中自动生成的index.html页面里,自动注入webpack打包的存在于内存中的bundle.js文件
        */
        new htmlWebpackPlugin({
            //页面模板
            template: path.join(__dirname, './src/index.html'),
            filename: 'index.html',
            minify: {
                collapseWhitespace: true, //合并多余的空格
                removeComments: true, // 移除注释
                removeAttributeQuotes: true //移除属性上的双引号
            }
        }),
        /*
            每次构建产物都要重新创建dist目录保存产物
        */
        new CleanWebpackPlugin({cleanAfterEveryBuildPatterns:['dist']}),

        new OptimizeCssAssetsPlugin()

        /*
            编译优化:抽离第三方包名称
            webpack3的在plugins数组中添加new webpack.optimize.CommonsChunkPlugin配置方式已经废弃,要在下面的方法进行实现
            webpack3实现方法
            new webpack.optimize.CommonsChunkPlugin({
                name: 'vendors', //指定抽离的入口
                filename: 'vendors.js' //抽离的所有第三方包的结果包名称。
            })
            webpack5设置无效,先注释
        */

        /*
            编译优化:js代码压缩优化
            new webpack.optimize.UglifyJsPlugin({
                compress: { //配置压缩项
                    warnings: false //移除警告
                }
            }),
            new webpack.optimize.DedupePlugin({
                'process.env.NODE_ENV': '"production"'
            })
        */

        /*
            编译优化:抽离css
            //配置提取出来的css名称
            new ExtractTextPlugin({
                filename: 'style/[name].min.css' 
            })
        */

    ],

    // webpack V5替代webpack V3的解决方案
    // optimization: {
    //     splitChunks: {
    //         cacheGroups: {
    //             commons: {
    //                 test: /[\\/]node_modules[\\/]/,
    //                 name: 'vendors',
    //                 chunks: 'all',
    //             },
    //         }
    //     }

    // },

    /*
        webpack默认只能打包处理以.js结尾的模块。其他非.js后缀名结尾的模块,webpack默认是不处理的。
        需要调用loader加载器才可以正常打包,loader加载器的作用:协作webpack打包处理约定的文件模块。比如:css-loader: 可以打包处理.css相关的文件。
        产物图片优化:
        把项目中的所有图片在产物中放到一个images文件夹下面
        { test: /\.(png|gif|bmp|jpg)$/, use: 'url-loader?limit=5000&name=images/[hash:8]-[name].[ext]' },
        
    */
    module: {
        rules: [
            { test: /\.css$/, use:['style-loader', 'css-loader'] },
            //声明css模块化,使用CSS模块化解决多个css的作用域都是全局作用域,导致结果互相覆盖的情况
            //一般第三方库的样式文件是以css结尾的,所以不能直接对css开启模块化,会影响其他第三方库的展示,这里只对scss进行开启模块化
            // { test: /\.css$/, use:['style-loader', {
            //     loader: 'css-loader',
            //     options: {
            //         importLoaders: 1,
            //         modules: true,
            //         //自定义css模块化后的class名称
            //         // localIdentName: [name]-[local]-[hash:5]
            //     }
            // }] },
            { test: /\.scss$/, use:['style-loader', {
                loader: 'css-loader',
                options: {
                    importLoaders: 1,
                    modules: true,
                    //自定义css模块化后的class名称
                    // localIdentName: [name]-[local]-[hash:5]
                }
            }, 'sass-loader'] },
            { test: /\.(png|gif|bmp|jpg)$/, use: 'url-loader?limit=500000' },
            { test: /\.jsx?$/, use:'babel-loader', exclude: /node_modules/ },
        ]
    }

}

对应package.json依赖关系和scripts短命令

复制代码
{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "--cacheBase": "指定托管目录, 如果没指定默认在项目内存的根目录下",
    "dev": "webpack-dev-server --open --port 3000 --hot",
    "pub": "webpack --config webpack.pub.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "7",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^6.8.1",
    "extract-text-webpack-plugin": "^3.0.2",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.5.3",
    "node-sass": "^9.0.0",
    "optimize-css-assets-webpack-plugin": "^6.0.1",
    "sass-loader": "^13.3.2",
    "style-loader": "^3.3.3",
    "url-loader": "^4.1.1",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
  },
  "dependencies": {
    "antd": "^5.10.1",
    "jquery": "^3.7.1",
    "prop-types": "^15.8.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "4.2.2"
  }
}

.babelrc模板

复制代码
{
    "presets": ["env", "stage-0", "react"],
    "plugins": ["transform-runtime"]
}