zoukankan      html  css  js  c++  java
  • webpack4进阶配置

    移动端CSS px自动转换成rem

    需要两步来实现:

    1. px2rem-loader 在构建阶段将px转换成rem
    2. lib-flexible 页面渲染时动态计算根元素的font-size值(手机淘宝开源库)

    下载插件并配置:

    npm i px2rem-loader lib-flexible
    
    module: {
       rules: [
          {
             test: /.less$/,
             use: [
                MiniCssExtractPlugin.loader, 
                "css-loader",
                {
                   loader: "postcss-loader",
                   ...
                },
                {
                   loader: "px2rem-loader",
                   options: {
                      remUnit: 75,
                      remPrecision: 8
                   }
                },
                "less-loader",
             ]
          },
       ]
    },

    然后,需要将淘宝的插件的内联在html文件中:

    <script src='../node_modules/lib-flexible/flexible.js'></script>

    静态资源内联

    静态资源内联是指将CSS、JS等静态文件中的内容抽离出来,内联到html中。我们之前借助插件做到了将内联的资源独立成文件,为什么还要将资源内联呢?

    资源内联的意义:

    • 代码层面:
    1. 页面框架的初始化脚本(这些脚本往往需要在第一时间加载,多将其写在<head>中)
    2. 上报相关打点
    3. CSS内联避免页面闪动
    4. HTML可以动态地将不同的meta标签内联进来
    • 请求层面:
    1. 减少http请求

    HTML和JS内联

    使用raw-loader,注意要使用0.5的版本,新版本的存在一些问题。

    npm i raw-loader@0.5.1
    
    /src/meta.html 【例:腾讯NOW直播官网的meta标签】
    <meta charset="UTF-8">
    <meta name="viewport" content="viewport-fit=cover,width=device-width,initial-scale=1,user-scalable=no">
    <meta name="format-detection" content="telephone=no">
    <meta name="keywords" content="now,now直播,直播,腾讯直播,QQ直播,美女直播,附近直播,才艺直播,小视频,个人直播,美女视频,在线直播,手机直播">
    <meta name="name" itemprop="name" content="NOW直播—腾讯旗下全民视频社交直播平台">
    <meta name="description" itemprop="description" content="NOW直播,腾讯旗下全民高清视频直播平台,汇集中外大咖,最in网红,草根偶像,明星艺人,校花,小鲜肉,逗逼段子手,各类美食、音乐、旅游、时尚、健身达人与你24小时不间断互动直播,各种奇葩刺激的直播玩法,让你跃跃欲试,你会发现,原来人人都可以当主播赚钱!">
    <meta name="image" itemprop="image" content="https://pub.idqqimg.com/pc/misc/files/20170831/60b60446e34b40b98fa26afcc62a5f74.jpg">
    <meta name="baidu-site-verification" content="G4ovcyX25V">
    <meta name="apple-mobile-web-app-capable" content="no">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    
    /node_modules/lib-flexible/flexible.js 【npm下载的淘宝库】
    
    
    /src/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        ${ require('raw-loader!./meta/meta.html') }
        <title>Hello Webpack</title>
        <script>${ require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') }</script> <!-- 先用raw-loader内联,再用babel-laoder转换语法 -->
    </head>
    <body>
    <div id="root"></div>
    </body>
    </html>

    CSS内联

    借助style-loader即可

    {
        loader: 'style-loader',
        options: {
            insertAt: 'top', // 样式插入到<head>
            singleton: true, // 将所有style标签合并成一个
        }
    }

    多页面应用打包方案

    每当增加一个页面,我们就手动地在webapck配置中对应增加一个entry、html-webpack-plugin。

    一定可以有更优的方案,那就是:动态获取entry的数量、然后自动生成html-webpack-plugin。

    需要借助glob.sync,可以在每次构建的时候获取页面的数量。这需要我们规范目录,将每个页面(文件夹)都放在src文件夹下,每个页面(文件夹)入口文件是index.js,入口页面是index.html。

    npm i glob
    
    const glob = require('glob');
    
    const setMPA = () => {
       let entry = {};
       let htmlWebpackPlugins = []; 
       const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js')); // 获取所有页面的入口文件路径。entryFiles是所有页面index.js的绝对路径形成的数组
    
       entryFiles.forEach((file)=>{
          let name = file.match(/src/(.*)/index.js/);
          let pageName = name && name[1];
          entry[pageName] = file;
          htmlWebpackPlugins.push(new HtmlWebpackPlugin({
             template: file.replace("index.js","index.html"),
             filename: `${pageName}.html`,
             chunks: [`${pageName}`],
             inject: true,
             minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: true,
             },
          }))
       });
    
       return {
          entry,
          htmlWebpackPlugins
       }
    };
    
    const result = setMPA();
    
    module.exports = {
       entry: result.entry,
    
       output: {
          filename: "bundle[chunkhash:8].js",
          path: path.join(__dirname, "/dist")
       },
       mode: 'production',
       module: {
          rules: [
              ...
          ]
       },
       plugins: [
          ...result.htmlWebpackPlugins, // 将N个HtmlWebpackPlugin对象插入列表
          new MiniCssExtractPlugin({
             filename: '[name][contenthash:8].css'
          }),
          new OptimizeCssAssetsPlugin({
             assetNameRegExp: /.css$/g,
             cssProcessor: require('cssnano'),
          }),
          new CleanWebpackPlugin(),
    };

    使用Source Map

    什么是source map?顾名思义,就是代码地图,可以将构建前后的两份代码做一个映射。

    sourcemap的作用:构建后的代码已经变了模样,没有可读性,开发调试的时候无法定位问题所在。sourcemap的存在可以直接将问题定位到源代码,排查问题。

    配置文件中devtool属性可以设置,有非常多的类型可选,一般情况下,开发环境使用"source-map",生产环境关闭。

    module.exports = {
       devtool: "source-map"
    };

    代码分割

    对于大型的web应用来说,将所有的代码编译成一个文件显示不好,会造成文件体积过大以及需要加载大量与首屏无关的代码,用户体验不好。webpack提供将代码分割成chunk(语块),当代码运行到需要的它们的时候再进行加载。

    代码分割有两种类型:

    • 抽离公共资源。(比如基础库入React/Vue,React-Router/Vue-Router。或者自己编写的公共模块)
    • JS懒加载,使得初始状态下的代码更小(首屏优化)

    抽离公共资源

    需要借助插件,有两个插件可供选择:html-webpack-externals-plugin 和 SplitChunsPlugin(webpack4内置,代替webpack3的CommonsChunkPlugin)

    说明:

    • 两个插件不要混用
    • html-webpack-externals-plugin既可以将本地基础库分离,也可以直接使用CDN。本人试图将本地库进行分离,总是失败,暂没查明原因。
    • 使用SplitChunksPlugin中chunks时,如果没有使用异步加载,chunks建议"all",但如果使用了异步加载,"all"则会导致错误,这时建议用"initial"

    html-webpack-externals-plugin:

    npm i html-webpack-externals-plugin
    
    const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
    
    plugins: [
          new HtmlWebpackExternalsPlugin({
             externals: [
                {
                   module: "react", // 代码中引入的库的名称
                   entry: "https://11.url.cn/now/lib/16.2.0/react.min.js",
                   // entry: "cjs/react", // 相对于node_modules/react的路径【官网示例,实际并不成功】
                   global: "React", // 代码中引入的库的全局对象的名称
                },
                {
                   module: "react-dom",
                   entry: "https://11.url.cn/now/lib/16.2.0/react-dom.min.js",
                   // entry: "dist/react-dom", // 相对于node_modules/react-dom的路径 【官网示例,实际并不成功】
                   global: "ReactDOM",
                },
    
             ],
          })
    ]

    SplitChunksPlugin:

    module.exports = {
       optimization: {
          splitChunks: {
             minSize: 0, // 分离包体积的最小大小
             cacheGroups: {
                commons: {
                   // test: /(react|react-dom)/,  // 通过正则匹配,只分离react/react-dom这两个库,不写test则不作限制
                   name: 'commonss',  // 分离块的名称,需要加在HtmlWebpackPlugin插件的chunks属性中,才能正确命名分离后的文件
                   chunks: "all", // 需要分割哪些代码块,all表示所有代码块,async按需加载的代码块,initial初始化代码块
                   // minChunks: 2, // 最小引用次数,少于这个引用次数就不会单独提取出来
                }
             }
          }
       }
    };

    JS懒加载

    实现懒加载不需要对webpack配置,动态引入import('')语法还没有成为JS标准(也许不久的将来会),目前要借助js插件

    实现懒加载:

    • 如果使用的CommonJS,直接require.ensure即可
    • 如果使用ES6模块化,需要借助第三方插件实现。(babel插件@babel/plugin-syntax-dynamic-import,且在.babelrc文件内配置)
    npm i @babel/plugin-syntax-dynamic-import
    
    .babelrc
    {
      "presets": [
        "@babel/preset-react",
        "@babel/preset-env"
      ],
      "plugins": [
        "@babel/plugin-syntax-dynamic-import",  // 懒加载插件
        "@babel/plugin-proposal-class-properties"
      ]
    }

    在此基础上,如果使用React开发项目,还可以使用react-loadable插件来更好的实现异步加载

    npm i react-loadable
    
    index.js中部分代码
    
    import Loadable from "react-loadable";
    const TextLoad = Loadable({
       loader: () => import(/* webpackChunkName: 'text' */    './text'), // 通过注释的方式指定打包后的chunk的名字
       loading: ()=> <div>正在加载</div>
    });
    
    class Search extends React.Component{
    
       constructor(props){
          super(props);
          this.state = {
             text: false,
          };
       }
    
       loadComponent = () => {
          this.setState({
             text: true
          })
       };
    
       render() {
          const { text } = this.state;
          return (
             <>
                <div>你好,显示字体 Hello Webpacks</div>
                {
                   text ? <TextLoad /> : null
                }
                <img alt="" src={logo} style={{  100 }} onClick={this.loadComponent}/>
             </>
          )
       }
    }
    
    export default Search;

    tree shaking(摇树优化)

    一个文件会有多个方法、对象、语句,只要用到其中一小部分,便会将整个文件内的所有内容打包进去。tree shaking只把用到的方法打包进去,没用到的会在uglfiy阶段被擦出掉。

    使用:webpack默认支持,生产环境默认开启

    要求:必须是ES6的写法,CommonJS的方式不支持

    Scope Hoisting

    构建之后的代码存在大量闭包,导致:

    • 文件体积增大
    • 运行代码时创建的函数作用于变多,内存开销变大

    scope hoisting就是减少闭包函数的声明。

    原理:将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当地重命名一些变量以防止变量名冲突,以此减少闭包函数声明代码。

    使用:webpack默认支持,生产环境默认开启

    要求:必须是ES6写法,CommonJS的方式不支持

    优化构件时命令行的显示日志

    每次构建,命令行输出大量日志,有很多是我们完全不关心的,想要优化它,可以在webpack中设置state属性。

    // 如果是打包,在最外层的state属性
    module.exports = {
       stats: 'errors-only',
    };
    // 如果是devserver热更新
    const devConfig = {
       devServer: {
          contentBase: './dist',
          hot: true,
          stats: 'errors-only', 
       },
    };

    state的取值有:

    • errors-only  只发生错误时输出
    • minimal       只发生错误或有新的编译时输出
    • none       没有输出
    • normal         标准输出
    • verbose       全部输出

    我们希望是在发生错误的时候输出,当state为error-only时,如果没有错误,没有任何输出,不太友好。

    借助插件:friendly-errors-webpack-plugin。此时将state设置成errors-only

    npm i friendly-errors-webpack-plugin
    
    const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
    module.exports = {
       plugins: [
          new FriendlyErrorsWebpackPlugin(),
       ],
    };
  • 相关阅读:
    Zabbix实现企业微信(WeChat)告警
    Zabbix使用腾讯企业邮箱发送警报邮件,在微信查看警报邮件
    centos7安装pip
    zabbix源码安装3.4.11客户端和yum安装4.2.1客户端
    zabbix中文乱码解决
    centos7配置阿里yum源替换centos自带的yum源(其他镜像yum源配置相似)
    CentOS7.5下Redis5.0.5安装与配置
    LVS+Keepalived搭建高可用负载均衡
    centos7配置双ip(内外网均可访问)
    NSMutableAttributedString 的使用
  • 原文地址:https://www.cnblogs.com/V587Chinese/p/11571515.html
Copyright © 2011-2022 走看看