• 重学webpack


    一:基本配置

    1. webpack默认的配置只能解析js,和json 

    webpack启动配置 内置了很多的函数功能,目的是为了让浏览器能解析我们js(因为还有浏览器不支持require ecports module)

    因为为了解决浏览器支持而内置的js功能,导致webpack不适合构建库;适合构建项目工程,用强大的编译功能提高效率

    vue、react源码是用rollup 代码比较纯粹。

    const path =  require('path')
    module.exports = {
    entry:'./src/index.js',
    mode:'development',
    // mode:'production', //会代码分割,会压缩,output后的文件是1.main.js
    output:{
    path:path.resolve(__dirname,'./dist'), //path:绝对路径的字符串
    filename:'main.js'
    }
    }

    2.webpack有默认的配置文件,叫webpack.config.js 

    "script":{
    "dev":"webpack",  //使用默认的配置文件
    "build":"webpack --config webpack-config.js" // 或者通过--config webpack-config.js 来指定webpack使用哪个配置文件来执行构建
    }

    3.entry (入口) 可以是字符串、数组、对象

    module.exports = {
     entry:'./src/index.js' //可以是字符串
     // 数组 entry:['./src/index.js']  // 多个数组元素会被打包到一个文件
    // 对象 entry:{
      // index:'./src/index.js'
       // }
    
    }

    多入口多出口 如果多入口一个出口就会出错

    entry:{
    main:'./src/index.js',
    other:'./src/other.js'
    },
    output:{
    path:path.resolve(__dirname,"./dist"),
    filename:"[name].js"  //name是占位符
    } 

    4. mode:none、development、production

    默认设置的是 production

    开发阶段的开启有利于热更新的处理,识别哪个模块的变化;

    生产阶段的开启有利于模块压缩、处理副作用等一些功能

    5.output -> filename:[name]_[chunkhash:8].js

    hash chunkhash contenthash

    hash 整个文件hash值都相同 一处改变 其他都会变

    chunkhash 对应的css和js文件改变 与其关联的hash值就会改变 但其内容并未改变 这样就达不到缓存的效果

    contenthash(针对内容,只要内容不一样,hash值就会不一样)

    js 推荐使用chunkhash

    在使用chunkhash时候 css改变后 引入css的js打包后文件也会改变。所以contenthash就出来了,针对内容改变才会去改变 

    css 推荐contenthash 把css都抽离出对应的css文件加以引用

    6.loader

    module:{
      rules:[
        {
          test:/.css$/,
        //loader的执行顺序 从右往左
      // css-loader: 把样式代码写入js ,这一步还不够,样式不起作用
      // style-loader:把写入的js样式,插入到index.html中 (html.head.style中)
          use:["style-loader","css-loader"]
       },
       {
         test:/.png$/,
         //use:["file-loader"] 
         //给loader添加参数
        use:{
          loader:'file-loader',
          options:{
          name:"[name].[ext]
          }
         }
        }
      ]
    } 

    7.plugins

    html-webpack-plugin

    //会在打包结束后,自动生成一个html文件,并把打包生成的js模块引入到html中
    const htmlWebpackPlugin = require("html-webpack-plugin-)
    plugins:[
      new htmlWebpackPlugin({
        title:'测试标题',
        template:'./index.html' ,//使用哪一个作为模板
        filename:'index.html', //打包后的filename
      })
      
    // 设置完标题后需要在index.html中 将title更换掉
    //<title> <%= htmlWebpackPlugin.options.title %></title>
    ]    

    clean-webpack-plugin

    plugins:[
    //在构建之前,将dist文件删除掉
    new CleanWebpackPlugin()
    ]

    mini-css-extract-plugin

    //把css提取成独立文件
    {
     test:/.css$/,
    use:[MiniCssExtractPlugin.loader,"css-loader"]
    }
    
    new MiniCssExtractPlugin({
    filename:"[name][chunkhash:8].css"
    })

    8.sourceMap 

    // none 若要关闭配置,则设置为none
    // source-map:产生.map文件、
    // eval:速度最快,使用eval包裹模块代码、
    // cheap:较快,不包含列信息、
    // Module:第三方模块,包含loader的sourcemap(比如jsx to js ,babel的sourcemap)、
    // inline:将.map作为dataURI嵌入,不单独生产.map文件
    
    配置推荐:
    devtool:"cheap-module-eval-source-map" //开发环境部署
    //线上不推荐开启devtool:暴露代码&影响解析速度
    devtool:'cheap-module-source-map'  //线上生成配置

    二.热更新&热模块更新

    热更新 每次修改后浏览器会自动刷新一次

    热模块更新 修改css 时候 局部更新

    webpack插件中自带了HotModuleReplacement (HMR)

    plugins:[
    webpack.HotModuleReplacementPlugin()
    ]

    可以在devServer.hot 设置为true 就会开启热更新

    hotOnly:true 无论代码如何改变 都不会刷新浏览器

    但是当手动更改原生js时候 需要手动的去监听

     if(module.hot){
     module.hot.accept('./index.js',()=>{
     //重新执行一遍操作
    })
    }

    用到vue、react、angular时候 webpack提供了相应的loader 例如vue-loader 只有原生js需要手动去监听变化然后热更新

    module:{
      rules:[
       {
        test:/.vue$/,
       loader:['vue-loader']
        }
    ]
    }
    css-loader:把css代码打包到js中 解析css 一般是 @import和url()两部分(样式不生效)
    style-loader:把写入的js代码插入到index.html的head中  (样式生效)
    vue-style-loader 同style-loader是把打包后的js代码中的css代码插入到index.html 他还可以处理.vue文件中的 <style> 模块中的样式代码 是没有热更新的 在ssr时候做了一些操作
    vue-loader 是针对vue框架采用的 有热更新
     
    三.babel
    需要安装
    //需要安装
    npm i babel-loader @babel/core @babel/preset-env -D

    1. babel-loader 是webpack与babel的通信桥梁,不会做 把es6转成es5的工作,这部分工作需要用到@babel/preset-env来做

    2. @babel/core提供了核心的库和API。 

    3. @babel/preset-env 里包含了es6、7、8转es5的转换规则

    {
       test:/.js$/,
       use:{
       loader:'babel-loader',
        options:{
            presets:["@babel/preset-env']
        }
       }
    }

    只转换了const let 箭头函数等一些基础的语法

    但是promise等新特性 低版本浏览器不知道

    方法:把新特性的语法引进来 polyfill (包含了所有新特性)

    //需要安装 @babel/polyfill
    nom i @babel/polyfill -S

    打包后的体积变大了,因为polyfill把所有新特性都引进来了,我们需要实现按需加载

    {
       test:/.js$/,
       use:{
       loader:'babel-loader',
        options:{
            presets:["@babel/preset-env',{
           targets:{
           edge:"17",
           firefox:"60",
           chrome:"67",
           safari:"11.1"
        },
        corejs:2, // 新版本需要指定核心库版本
        useBuiltIns:"usage" //按需注入 ,有3个可选值,推荐使用usage
       }]
        }
       }
    }

    polyfill与transform-runtime的区别 

    polyfill是以什么方式引入新特性:直接挂在全局对象上 window 造成的后果:会污染全局变量

    polyfill 不适合构建开源库 UI库

    当我们开发组件库,工具库的时候 polyfill就不适合了,因为polyfill是注入到全局变量,window下会污染全局环境,所以推荐闭包方式:@babel/plugin-transform-runtime 它不会造成全局污染

    transform-runtime

    //需要安装
    npm i @babel/plugin-transform-runtime -D
    npm i @babel/runtime -S
    {
      test:/.js$/,
      use:{
     loader:'babel-loader',
     "plugins":[
     [
        "@babel/plugin-transform-runtime",
     {
       "absoluteRuntime":false,
       "corejs":false,
        "helpers":true,
        "regenreator":true,
       "useESModules":false
     }]
    ]
    }
    }

     可以把上述代码抽出来,放在.babelrc文件中

     {  
    "presets":[
      ["@babel/preset-env',{
           targets:{
           edge:"17",
           firefox:"60",
           chrome:"67",
           safari:"11.1"
        },
        corejs:2, // 新版本需要指定核心库版本
        useBuiltIns:"usage" //按需注入 ,有3个可选值,推荐使用usage
       }]
    ],
    //plugins 当react代码不是用jsx的语法 而是 createElement的方式 ,需要将react转化一下
    //vue 就用 transform-vue-jsx
    "plugins":["@babel/presets-react"]
    }

     三.webpack 性能优化(能用绝对路径的就用绝对 绝对查询速度高于相对)

    1.loader 

     include & exclude

    2. 

    resolve:{
    //用来配置webpack去哪里找第三方相关的模块
    modules:[path.resolve(__dirname,"./node_modules")],
    //设置别名 来将原导入路径映射成一个新的导入路径
    //默认情况下,webpack会从入口文件 ./node_modules/bin/react/index开始递归解析和处理依赖文件,我们可以直接指定文件,避免此处的耗时
    alias:{
     "@":path.join(__dirname,"src"),
    "react":path.resolve(__dirname,"./node_modules/react-dom/umd/react.production.min.js"),
    "react-dom"...
    },
    //在导入语句没带后缀时,webpack会自动带上后缀后,去查找文件是否存在
    // 后缀尝试列表尽量的少,导入语句尽量带上后缀
    extensions:[".js",".json"]
    }

     3.tree shaking

    ①.css 

    npm i glob-all purify-css purifycss-webpack --save-dev
    
    const PurifyCSS = require('purifycss-webpack')
    const glob = require('glob-all')
    
    plugins:[
    
    new PurifyCSS({
     path:glob.sync([
      //要做css tree shaking的路径文件
       path.resolve(__dirname,'./src/*.html')  //请注意,我们同样需要对html文件进行tree shaking
        path.resolve(__dirname,'./src/*.js')
      ])
    })
    ]

    ②.js(只支持es module 的模块方式 import方式引入,不支持commonjs  require的方式引入)

    js tree shaking在开发模式下 是不生效的 只有在生产环境才会生效 为了方便调试

    optimization:{
       usedExports:true //哪些导出的模板被使用了
    }

    只要将mode设置为production 就会自动开启js 摇树功能

     4. V8带来的优化

    ①:for...of替代forEach

    ②:Map和Set替代Array和Object

    ③:includes替代indexOf

     
  • 相关阅读:
    讨论下NOSQLDB使用场景的问题
    控制反转IOC与依赖注入DI dodo
    ASp.net中Froms验证方式 dodo
    SQL Server 2008阻止保存要求重新创建表的更改 dodo
    依赖注入容器Unity介绍 dodo
    mvc UrlHelper dodo
    ASP.NET MVC 使用TempData dodo
    ASP.NET MVC的生命周期与网址路由 dodo
    强制将IE,Chrome设置为指定兼容模式来解析 dodo
    LINQ to XML 常用操作(转) dodo
  • 原文地址:https://www.cnblogs.com/alhh/p/13071545.html
Copyright © 2020-2023  润新知