让前端飞Web前端之路

webpack使用与配置(下)

2019-06-18  本文已影响0人  XJBT

对于之前webpack使用与配置(上)
的补充

  1. 使用typescript时需要在根目录下创建一个tsconfig.js的文件

  2. 关于.babelrc的配置

    • 直接在webpack.config.js中配置options
    • 创建.babelrc文件,在该文件中配置
    • 注意二者取其一就行了,当然也可以两者互补,只要两者合并起来能满足配置需求即可

    webpack.config.js中的配置是这样的:

        {
            test: /\.js$/, // normal 普通的 loader
            use: {
                loader: 'babel-loader',
                options: { // 用babel-loader 需要把 es6 -> es5
                    presets: [
                        '@babel/preset-env',
                        '@babel/preset-react'
                    ],
                    plugins: [
                        ["@babel/plugin-proposal-decorators", { "legacy": true }], // 装饰器语法
                        ["@babel/plugin-proposal-class-properties", { "loose": true }], // 支持 class 语法
                        "@babel/plugin-transform-runtime", // 运行时,支持 promise 或 gen*
                        "@babel/plugin-syntax-dynamic-import", // 支持 import then 语法
                    ]
                }
            },
            include: path.resolve(__dirname, '../src'), // 指定为 src 文件
            exclude: /node_modules/, // 排除 node_modules
        }
    

    .babelrc中的配置是这样的:

        {
            presets: [
                '@babel/preset-env',
                '@babel/preset-react'
                // 使用react必须配置的presets项
            ],
            plugins: [
                ["@babel/plugin-proposal-decorators", { "legacy": true }], // 装饰器语法
                ["@babel/plugin-proposal-class-properties", { "loose": true }], // 支持 class 语法
                "@babel/plugin-transform-runtime", // 运行时,支持 promise 或 gen*
                "@babel/plugin-syntax-dynamic-import", // 支持 import then 语法
            ]
        }
    

    终于可以摆脱脚手架了。。。。。*(幼稚的想法)

  3. hashchunkhashcontenthash的配置

    • hash 计算是跟整个项目的构建相关,也就是说如果配置的是hash,那么只要项目中一个文件发生变化,那么所有的hash都会发生变化,这对缓存来说是一种浪费,使用hash时所有的hash值都是一样的,发生变化时一起变化
    • chunkhash 就是解决上面这个问题的,它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。即一个chunk里面修改的内容不会影响到另一个chunk,只有自己这个chunkchunkhash会发生变化
      • 我们更近一步,index.jsindex.css 同为一个 chunkindex.css是同一个chunk里面抽出来的),如果 index.js 内容发生变化,但是 index.css 没有变化,打包后他们的 hash 都发生变化,这对 css 文件来说是一种浪费。如何解决这个问题呢?contenthash 将根据资源内容创建出唯一 hash,也就是说文件内容不变,hash 就不变。
  4. mini-css-extract-plugin的使用姿势:

    • 先是装包,在plugins里面new出来一个实例
        new MiniCssExtractPlugin({
            filename: 'index.[contenthash:8].css'
            // 使用contenthash的好处见上一条
        }),
    
    • 修改rules里面的配置,现在不是用style-loader了,而是要利用mini-css-extract-plugin提供的loader
        {
            test: /\.scss$/,
            use: [
                // 这里替换了原来的style-loader
                { 
                    loader: MiniCssExtractPlugin.loader,
                    options: {
                        hmr: true,
                        reloadAll: true
                    }
                }, 
                {
                    loader: 'css-loader',
                    options: {
                        modules: true
                    }
                }, 
            'sass-loader', 'postcss-loader'],
        }
    

    如果不抽离css文件那么所有的css样式内容都会在打包后被放在bundle.js文件中,造成的结果就是bundle.js文件内容过大,如果是一个单页应用的话,需要花更多的时间去下载bundle.js,首屏体验就不好,抽离css文件的作用应该就是这个,将css样式的内容抽离出css文件,通过link标签引入index.html中,这样在下载css内容的时候可以继续构建DOM树也可以继续下载后面的bundle.js,阻塞的只是DOM的渲染和bundle.js的执行,总体来说是提升了性能的。

  5. optimize-css-assets-webpack-plugin
    这个插件用于对css资源进行压缩,食用方式是在optimization里面进行配置

        const OptimizeCss = require('optimize-css-assets-webpack-plugin')
        const Uglify = require('uglifyjs-webpack-plugin')
    
        mode: 'production',
        optimization: {
            minimizer: [
                new OptimizeCss(),
                new Uglify(),
            ],
        },
    

    注意:虽然mode已经设置为production,但是使用了optimize-css-assets-webpack-plugin插件之后如果不使用uglifyjs插件的话js文件将无法压缩,展现出来的是和development模式是一样的,当然如果设置的是development模式的话,即使使用了uglifyjs插件也无法压缩。

  6. externals配置
    譬如通过<script></script>标签引入了jQueryCDN,此时在文件中使用$或者window.$都可以直接使用jQuery,也不需打包进bundle.js,但是如果此时又写了import $ from 'jquery'(纯属为了看着顺眼);的话,jQuery又会被打包进bundle.js,为了避免这样的情况(不用引入的情况偏偏引入了,又不想打包),可以通过配置externals属性来忽略一些不需要打包的内容

        externals: {
            jquery: '$',
        }
    
  7. 在处理图片时,有三种情况

    • js文件中创建img,然后添加进DOM tree
          import imgSrc from './a.jpg';
          const image = new Image()
          image.src = imgSrc
      
    • css文件中作为background使用
      {
          backgroung: url('./a.jpg');
          // 此时不需要先引入,是因为css-loader已经做了这一步操作
      }
      
    • html文件中直接使用
          <img src='./a.jpg' />
      
      为了将该src转化为图片打包后的地址,使用一个loaderhtml-withimg-loader
          {
              test: /\.html$/,
              loader: 'html-withimg-loader'
          }
      

    注意:在配置webpack.config.js时可以像下面这样配置,但是虽然我们只使用了url-loader,但是需要同时装包file-loader,因为由于limit的限制,当图片文件大于200K时会使用file-loader打包出一个图片文件放在build文件夹下,图片大小小于limit限制时是以base64的形式打包进bundle.js文件,也就是说url-loader里面可能会使用到file-loader,这样做的目的也是为了防止bundle.js文件过大,另一个原因是图片过大时编码需要的时间较长,影响打包的速度。但是如果图片较多,会发很多 http 请求,会降低页面性能,所以当图片体积较小时 url-loader 会将引入的图片编码,转为 base64 字符串。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了,节省了图片请求。

    ```
        {
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'url-loader',
                options: {
                    limit: 200*1024,
                    outputPath: 'img/'
                    // 会在build目录下创建一个img目录
                }
            }
        },
    ```
    
  8. 关于publicPath的配置,这是代码上线后将资源托管在CDN服务器上,此时html文件中引入各个bundle.js文件不再是本地引入,而是要去CDN服务器上引入,如果继续写成./bundle.js就无法获取到资源,所以就要给所有的引入路径添加上一个公共的路径,譬如说放在http://www.navyblue.com/CDN服务器上,那么publicPath就设置为http://www.navyblue.com/,这时候在html引入bundle.js的时候就会自动去引入http://www.navyblue.com/bundle.js。如果在output中配置publicPath那么打包出来的所有结果被引入时都会加上公共路径,如果想单独配置,譬如说只给图片加,那么就可以在url-loaderoptions里面配置
    { test: /\.(jpg|png|gif)$/, use: { loader: 'url-loader', options: { limit: 200*1024, outputPath: 'img/', // 会在build目录下创建一个img目录 publicPath: 'http://www.navyblue.com/' } } },

  9. 关于chunkbundlemodule的区别:

    • module好理解,就是需要被打包的一个个模块
    • bundle就是打包出来的一个个js文件
    • chunk:一个entrypoint进去以后,根据各种依赖关系形成一大个chunk,如果在打包一个chunk的过程中需要分割代码,那么分割完最后得到的一个个包就是bundle
  10. 关于html-webpack-plugin的使用: 对于多页应用需要new多个plugin出来

        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                removeAttributeQuotes: true,
            },
            filename: 'home.html',
            // filename是打包结束后输出的html文件名
            chunks: ['main'],
            // chunks是指该html需要引入的js文件,里面的`main`其实就是一个entrypoint,因为一个entrypoint对应的就是一个chunk
        }),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                removeAttributeQuotes: true,
            },
            filename: 'other.html',
            chunks: ['sub'],
        }),
    
  11. resolve的配置:

        resolve: { //  解析模块的可选项
            modules: [ // 模块的查找目录
                "node_modules",
                path.resolve(__dirname, "app")
            ],
            extensions: [".js", ".json", ".jsx", ".css"], // 用到的文件的扩展
            alias: { // 模块别名列表
                "module": "new-module"
                // 用到的别名:真正的路径
            },
        },
    
  12. production mode(生产模式) 可以开箱即用地进行各种优化。 包括压缩,作用域提升,tree-shaking 等。

  13. 对于cacheGroups的配置:

        splitChunks: {
            chunks: 'all',
            minSize: 50000,
            minChunks: 2,
            // 内部的minChunks可以覆盖这里的minChunks
            cacheGroups: {
                lodash: {
                    name: 'mylodash',
                    test: /[\\/]node_modules[\\/]lodash/,
                    // 选择匹配的模块
                    // 譬如第一个包打包的只有lodash,因为没匹配到react所以不会分割到这个包里
                    minChunks: 1,
                    priority: 10,
                    // 打包会根据priority的大小从大到小打包
                },
                react: {
                    name: 'myreact',
                    test: /[\\/]node_modules[\\/]react/,
                    minChunks: 1,
                    priority: 5,
                },
                vendors: {
                    name: 'myGroups',
                    test: /[\\/]node_modules1[\\/]/,
                    priority: -10,
                    minChunks: 1,
                },
                default: {
                    name: 'default',
                    // 默认有个default配置,但是如果显示写出来又全都没匹配中的话会再次调用一个隐式的default
                    minChunks: 1,
                    priority: -20,
                }
            }
        },
    
  14. @babel/polyfill

Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如IteratorGeneratorSetMapProxyReflectSymbolPromise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。

举例来说,ES6Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用@babel-polyfill,为当前环境提供一个垫片,使得在当前环境下可以执行该方法。

  1. 关于CSS代码

css-loader:负责解析 CSS 代码,主要是为了处理 CSS 中的依赖,例如 @importurl() 等引用外部文件的声明

style-loader 会将 css-loader 解析的结果转变成 JS 代码,运行时动态插入 style 标签来让 CSS 代码生效。

上一篇下一篇

猜你喜欢

热点阅读