• webpack4.x最详细使用讲解三


    七、项目优化及拓展

    7.1 代码分离

    在当前的开发环境都是提倡模块化,webpack自然不例外,我们前面的webpack.config.js配置文件,其实也没配置多少东西就这么多了,要是以后增加了更多配置,岂不是看得眼花缭乱,所以最好的方法就是把它拆分,方便管理:

    1. 我们在根目录下新建三个文件,分别为webpack.common.jswebpack.dev.jswebpack.prod.js,分别代表公共配置文件、开发环境配置文件、生产环境(指项目上线时的环境)配置文件。

    2. 安装一个合并模块插件:

    cnpm i webpack-merge -D

    3. 将webpack.config.js的代码拆分到上述新建的三个文件中,然后把webpack.config.js文件删除,具体如下:

    // webpack.common.js
    const path = require('path');  // 路径处理模块
    const webpack = require('webpack');  // 这个插件不需要安装,是基于webpack的,需要引入webpack模块
    const HtmlWebpackPlugin = require('html-webpack-plugin'); // 引入HtmlWebpackPlugin插件
    
    module.exports = {
        entry: path.join(__dirname, "/src/index.js"), // 入口文件
        output: {
            path: path.join( __dirname, "/dist"), //打包后的文件存放的地方
            filename: "bundle.js" //打包后输出文件的文件名
        },
        module: {
            rules: [
                {
                    test: /.css$/,   // 正则匹配以.css结尾的文件
                    use: ['style-loader', 'css-loader']  // 需要用的loader,一定是这个顺序,因为调用loader是从右往左编译的
                },
                {
                    test: /.(scss|sass)$/,   // 正则匹配以.scss和.sass结尾的文件
                    use: ['style-loader', 'css-loader', 'sass-loader']  // 需要用的loader,一定是这个顺序,因为调用loader是从右往左编译的
                },
                {                             // jsx配置
                    test: /(.jsx|.js)$/,   
                    use: {                    // 注意use选择如果有多项配置,可写成这种对象形式
                        loader: "babel-loader"
                    },
                    exclude: /node_modules/   // 排除匹配node_modules模块
                }
            ]
        },
        plugins: [
            new webpack.BannerPlugin('版权所有,翻版必究'),  // new一个插件的实例 
            new HtmlWebpackPlugin({
                template: path.join(__dirname, "/src/index.template.html")// new一个这个插件的实例,并传入相关的参数
            }),
            new webpack.HotModuleReplacementPlugin()
        ]
    }
    // webpack.dev.js
    const merge = require('webpack-merge');  // 引入webpack-merge功能模块
    const common = require('./webpack.common.js'); // 引入webpack.common.js
    
    module.exports = merge(common, {   // 将webpack.common.js合并到当前文件
        devServer: {
            contentBase: "./dist",   // 本地服务器所加载文件的目录
            port: "8088",  // 设置端口号为8088
            inline: true,  // 文件修改后实时刷新
            historyApiFallback: true, //不跳转
            hot: true     //热加载
        }
    })
    // webpack.prod.js
    const merge = require('webpack-merge');
    const common = require('./webpack.common.js');
    const CleanWebpackPlugin = require('clean-webpack-plugin'); // 引入CleanWebpackPlugin插件
    
    module.exports = merge(common, { // 将webpack.common.js合并到当前文件
        devtool: 'source-map',  // 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
        plugins: [
            new CleanWebpackPlugin(['dist']),  // 所要清理的文件夹名称
        ]
    })

    此时我们的项目目录如下:

    4. 设置package.json的scripts命令:

    {
      "name": "webpack-project",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "build": "webpack --config webpack.prod.js",
        "dev": "webpack-dev-server --open --config webpack.dev.js"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "babel-core": "^6.26.3",
        "babel-loader": "^7.1.5",
        "babel-preset-env": "^1.7.0",
        "babel-preset-react": "^6.24.1",
        "clean-webpack-plugin": "^0.1.19",
        "css-loader": "^1.0.0",
        "html-webpack-plugin": "^3.2.0",
        "node-sass": "^4.9.4",
        "react": "^16.6.0",
        "react-dom": "^16.6.0",
        "sass-loader": "^7.1.0",
        "style-loader": "^0.23.1",
        "webpack": "^4.23.1",
        "webpack-cli": "^3.1.2",
        "webpack-dev-server": "^3.1.10",
        "webpack-merge": "^4.1.4"
      }
    }

     我们把build命令改为了webpack --config webpack.prod.js,意思是把打包配置指向webpack.prod.js配置文件,而之前我们只需要使用一个webpack命令为什么就可以运行了?因为webpack命令是默认指向webpack.config.js这个文件名称了,现在我们把文件名称改了,所以就需要自定义指向新的文件,dev命令中的指令也同理。

    然后我们运行npm run buildnpm run dev,效果应该和我们分离代码前是一样的。

    注:说道package.json文件,顺便就多提几句,因为也许有些朋友可能对我们安装模块时加的-D-S-g命令存在一些疑惑,因为不知道什么时候加什么尾缀。
    其实这个package.json文件是用于我们安装依赖的,可以把它当成一份依赖安装说明表,就是如果我们把项目上传或者发给其他的开发同事,肯定不会把/node_modules文件夹也发送过去,因为这太大了,不现实也没必要。
    开发同事只需要有这份package.json文件,然后npm install就可以把我们所需要的依赖都安装下来,但前提是package.json文件上有记录,这就是安装模块时加上-D,-S命令的原因。
    -D的全称是--save-dev指开发环境时需要用到的依赖,会记录在package.json文件中的devDependencies选项中,而-S--save是指生产环境也就是上线环境中需要用到的依赖,会记录在package.json文件中的dependencies选项中,-g的全称是--global指安装全局命令,就是我们在本电脑的任何项目中都能使用到的命令,比如安装cnpm这个淘宝镜像命令就会用到-g命令。
    所以我们在安装模块时一定不要忘了加上对应的尾缀命令,让我们的模块有迹可循,否则其他的开发同事接手你的项目的话,会不会下班后(放学后)在门口等你就不知道了。

    扯远了,希望不要嫌弃,也是想讲得更详细嘛!

    7.2 多入口多出口

    到目前为止我们都是一个入口文件和一个出口文件,要是我不止一个入口文件呢?下面我们来试试:

    webpack.common.js中的entry入口有三种写法,分别为字符串、数组和对象,平时我们用得比较多的是对象,所以我们把它改为对象的写法,首先我们在src文件夹下新建two.js文件,名称任意。因为有多个入口,所以肯定得多个出口来进行一一对应了,所以entryoutput配置如下:

    // webpack.common.js
    ...
    module.exports = {
        entry: {
            index: path.join(__dirname, "/src/index.js"),
            two: path.join(__dirname, "/src/two.js")
        }, 
        output: {
            path: path.join( __dirname, "/dist"), //打包后的文件存放的地方
            filename: "[name].js" //打包后输出文件的文件名
        },
        ...
    }
    // two.js
    function two() {
        let element = document.createElement('div');
        element.innerHTML = '我是第二个入口文件';
        return element;
    }
    
    document.getElementById('root').appendChild(two());

    然后我们运行npm run build打包后发现/dist文件夹下会多出two.js文件,同时index.html也会自动将two.js引入,然后我们运行npm run dev显示如下:

    7.3 增加css前缀、分离css、消除冗余css、分离图片

    1.增加css前缀

    平时我们写css时,一些属性需要手动加上前缀,比如-webkit-border-radius: 10px;,在webpack中我们能不能让它自动加上呢?那是必须的,首先肯定得安装模块了:

    cnpm i postcss-loader autoprefixer -D

    安装好这两个模块后,在项目根目录下新建postcss.config.js文件:

    // postcss.config.js
    module.exports = {
        plugins: [
            require('autoprefixer')  // 引用autoprefixer模块
        ]
    }

    在style.css中增加以下样式:

    /* style.css */
    body {
        background: #999;
    }
    
    #root div{
         200px;
        margin-top: 50px;
        transform: rotate(45deg); /* 这个属性会产生前缀 */
    }

    修改webpack.common.js文件中的css-loader配置:

    ...
    module.exports = {
        ...
        module: {
            rules: [
                {
                    test: /.css$/,   // 正则匹配以.css结尾的文件
                    use: [            
                        {loader: 'style-loader'}, // 这里采用的是对象配置loader的写法
                        {loader: 'css-loader'},
                        {loader: 'postcss-loader'} // 使用postcss-loader
                    ]  
                },
                ...
            ]
        },
        ...
    }

    然后我们运行npm run dev后css样式中会自动添加前缀,显示如下:

    2.分离css

    虽然webpack的理念是把css、js全都打包到一个文件里,但要是我们想把css分离出来该怎么做呢?

    cnpm i extract-text-webpack-plugin@next -D  // 加上@next是为了安装最新的,否则会出错

     安装完以上插件后在webpack.common.js文件中引入并使用该插件:

    // webpack.common.js
    ...
    const ExtractTextPlugin = require('extract-text-webpack-plugin') //引入分离插件
    
    module.exports = {
        ...
        module: {
            rules: [
                {
                    test: /.css$/,   // 正则匹配以.css结尾的文件
                    use: ExtractTextPlugin.extract({  // 这里我们需要调用分离插件内的extract方法
                        fallback: 'style-loader',  // 相当于回滚,经postcss-loader和css-loader处理过的css最终再经过style-loader处理
                        use: ['css-loader', 'postcss-loader']
                    })
                },
                ...
            ]
        },
        plugins: [
            ...
            new ExtractTextPlugin('css/index.css') // 将css分离到/dist文件夹下的css文件夹中的index.css
        ]
    }

    运行npm run build后会发现/dist文件夹内多出了/css文件夹及index.css文件。

    3.消除冗余css

    有时候我们css写得多了,可能会不自觉的写重复了一些样式,这就造成了多余的代码,上线前又忘了检查,对于这方面,我们应该尽量去优化它,webpack就有这个功能。

    cnpm i purifycss-webpack purify-css glob -D

    安装完上述三个模块后,因为正常来说是在生产环境中优化代码,所以我们应该是在webpack.prod.js文件中进行配置,引入clean-webpack-pluginglob插件并使用它们:

    // webpack.prod.js
    const merge = require('webpack-merge');
    const common = require('./webpack.common.js');
    const CleanWebpackPlugin = require('clean-webpack-plugin'); // 引入CleanWebpackPlugin插件
    
    const path = require('path');
    const PurifyCssWebpack = require('purifycss-webpack'); // 引入PurifyCssWebpack插件
    const glob = require('glob');  // 引入glob模块,用于扫描全部html文件中所引用的css
    
    module.exports = merge(common, {   // 将webpack.common.js合并到当前文件
        devtool: 'source-map',  // 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
        plugins: [
            new CleanWebpackPlugin(['dist']),  // 所要清理的文件夹名称
            new PurifyCssWebpack({
                paths: glob.sync(path.join(__dirname, 'src/*.html')) // 同步扫描所有html文件中所引用的css
            })
        ]
    })

    我们在style.css文件中增加一些多余的代码试试:

    /* style.css */
    body {
        background: #999;
    }
    
    #root div{
         200px;
        margin-top: 50px;
        transform: rotate(45deg); /* 这个属性会产生前缀 */
    }
    
    .a{                 /* 冗余css */
        color: black;     
    }
    
    .b{                 /* 冗余css */
         50px;
        height: 50px;
        background: yellow;
    }

    然后我们运行npm run build后发现打包后的index.css中是没有多余的.a和.b代码的:

    /* index.css */
    
    body {
      background: #999;
    }
    
    #root div {
       200px;
      margin-top: 50px;
      -webkit-transform: rotate(45deg);
      transform: rotate(45deg);
      /* 这个属性会产生前缀 */
    }
    /*# sourceMappingURL=index.css.map*/

    4.处理图片

    到目前为止我们还没讲到图片的问题,如果要使用图片,我们得安装两个loader:

    // 虽然我们只需使用url-loader,但url-loader是依赖于file-loader的,所以也要安装
    cnpm i url-loader file-loader -D 

    然后在webpack.common.js中配置url-loader:

    // webpack.common.js
    ...
    module.exports = {
        ...
        module: {
            rules: [
                {
                    test: /.css$/,   // 正则匹配以.css结尾的文件
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: ['css-loader', 'postcss-loader']
                    })
                },
                {
                    test: /.(png|jpg|svg|gif)$/,  // 正则匹配图片格式名
                    use: [
                        {
                            loader: 'url-loader'  // 使用url-loader
                        }
                    ]
                },
                ...
            ]
        },
        ...
    }

    我们修改一下style.css,把背景改为图片背景:

    /* style.css */
    body {
        background: url(../images/coffee.png) top right repeat-y;  /* 设为图片背景 */
    }
    
    #root div{
         200px;
        margin-top: 50px;
        transform: rotate(45deg); /* 这个属性会产生前缀 */
    }
    
    .a{
        color: black;
    }
    
    .b{
         50px;
        height: 50px;
        background: yellow;
    }

    运行npm run dev后显示如下:

    但是背景图片变成了base64,因为webpack会自动优化图片,减少发送请求,但是如果我想把它变成路径的该怎么做?

    我们可以把webpack.common.js的loader配置更改一下,增加options选项:

    // webpack.common.js
    ...
    module.exports = {
        ...
        module: {
            rules: [
                {
                    test: /.css$/,   // 正则匹配以.css结尾的文件
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: ['css-loader', 'postcss-loader']
                    })
                },
                {
                    test: /.(png|jpg|svg|gif)$/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1000  // 限制只有小于1kb的图片才转为base64,例子图片为1.47kb,所以不会被转化
                            }
                        }
                    ]
                },
                ...
            ]
        },
        ...
    }

    然后我们运行npm run build后,再运行npm run dev,额,图片是没有转成base64了,但是图片怎么不显示了?

    问题就出在路径上,我们之前图片的路径是在../images文件夹下,但是打包出来后没有这个路径了,图片直接和文件同级了,所以我们需要在webpack.common.js中给它设置一个文件夹:

    // webpack.common.js
    ...
    module.exports = {
        ...
        module: {
            rules: [
                ...
                {
                    test: /.(png|jpg|svg|gif)$/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1000,  // 限制只有小于1kb的图片才转为base64,例子图片为1.47kb,所以不会被转化
                                outputPath: 'images'  // 设置打包后图片存放的文件夹名称
                            }
                        }
                    ]
                },
                ...
            ]
        },
        ...
    }

     继续npm run build打包再npm run dev运行,我的天!图片还是不显示!

    调试工具上看图片路径有images文件夹了,但是我的../呢?

    这又涉及到配置路径的问题上了,我们还需要在css-loader中给背景图片设置一个公共路径publicPath: '../',如下:

    // webpack.common.js
    ...
    module.exports = {
        ...
        module: {
            rules: [
                {
                    test: /.css$/,   // 正则匹配以.css结尾的文件
                    use: ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: ['css-loader', 'postcss-loader'],
                        publicPath: '../'  // 给背景图片设置一个公共路径
                    })
                },
                {
                    test: /.(png|jpg|svg|gif)$/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1000,  // 限制只有小于1kb的图片才转为base64,例子图片为1.47kb,所以不会被转化
                                outputPath: 'images'  // 设置打包后图片存放的文件夹名称
                            }
                        }
                    ]
                },
                ...
            ]
        },
        ...
    }

     现在再npm run build打包再npm run dev启动,OK!没毛病!

    是不是很热闹?到现在我们不知不觉中也同时解决了图片分离的问题,偷偷高兴一下吧!

    7.4 压缩代码

    在webpack4.x版本中当你打包时会自动把js压缩了,而且npm run dev运行服务器时,当你修改代码时,热更新很慢,这是因为你修改后webpack又自动为你打包,这就导致了在开发环境中效率很慢,所以我们需要把开发环境和生产环境区分开来,这时就体现出我们代码分离的便捷性了,webpack.dev.js代表开发环境的配置,webpack.prod.js代表生产环境的配置,这时我们只要在package.json文件中配置对应环境的命令即可:

    {
      ...
      "scripts": {
        "build": "webpack --config webpack.prod.js --mode production",
        "dev": "webpack-dev-server --open --config webpack.dev.js --mode development"
      },
      ...
      }
    }

     --mode production表示打包时是生产环境,会自己将js进行压缩,而--mode development表示当前是开发环境,不需要进行压缩。这同时也解决了之前一直遗留的警告问题:

    总结

    好了,到现在我们基本把webapck常用的功能都走了一遍,写得有点长,感谢你能仔细的看到这里,希望能对你有所帮助,如果有发现不对的地方,也请多多指教。其实webpack还有很多功能,这里也没讲述完全,但相信你现在对webpack也有了一定的了解,更多的webpack探索一定难不倒你!

  • 相关阅读:
    POJ 1035-Spell checker(字符串)
    No valid host was found
    Does anyone successfully use USB drive in Windows7 guest?
    iptables 问题
    openstack kilo版本控制节点异常流量分析
    openstack 控制节点大流量对外发包,nf_conntrack,table full droping packets
    Error: rpmdb open failed
    openstack message queue
    POJ 1700 经典过河问题(贪心)
    树莓派遥控船项目计划
  • 原文地址:https://www.cnblogs.com/samve/p/12386735.html
Copyright © 2020-2023  润新知