zoukankan      html  css  js  c++  java
  • webpack4学习

    一.安装前先npm初始化

    1 npm init -y
    2 npm i webpack webpack-cli -D

    创建webpack.config.js文件

    let path = require('path')   // 相对路径变绝对路径
    
    module.exports = {
      mode: 'production', // 模式 默认 production development
      entry: './src/index',    // 入口
      output: {
        filename: 'bundle.[hash:8].js',   // hash: 8只显示8位
        path: path.resolve(__dirname, 'dist'),
        publicPath: ''  // // 给所有打包文件引入时加前缀,包括css,js,img,如果只想处理图片可以单独在url-loader配置中加publicPath
      }
    }

    二.本地服务

    npm i webpack-dev-server -D
    devServer: {
      port: 3000,
      progress: true          // 滚动条
      contentBase: './build'  // 起服务的地址
      open: true              // 自动打开浏览器
      compress: true         // gzip压缩
    }

    三.处理html

    npm i html-webpack-plugin -D
    let HtmlWebpackPlugin = require('html-webpack-plugin')
    plugins: [ // 放着所有webpack插件
      new HtmlWebpackPlugin({ // 用于使用模板打包时生成index.html文件,并且在run dev时会将模板文件也打包到内存中
        template: './index.html', // 模板文件
        filename: 'index.html', // 打包后生成文件
        hash: true, // 添加hash值解决缓存问题
        minify: { // 对打包的html模板进行压缩
          removeAttributeQuotes: true, // 删除属性双引号
          collapseWhitespace: true // 折叠空行变成一行
        }
      })
    ] 

    html-webpack-plugin#options

    四.处理css

    npm i css-loader style-loader -D
    // css-loader   作用:用来解析@import这种语法
    // style-loader 作用:把 css 插入到head标签中
    // loader的执行顺序: 默认是从右向左(从下向上)
    module: {    // 模块
      rules: [   // 规则
        // style-loader 把css插入head标签中
        // loader 功能单一
        // 多个loader 需要 []
        // 顺便默认从右到左
        // 也可以写成对象方式
        {
          test: /.css$/,   // css 处理
          // use: 'css-loader'
          // use: ['style-loader', 'css-loader'],
          use: [
            // {
            //     loader: 'style-loader',
            //     options: {
            //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
            //     }
            // },
            MiniCssExtractPlugin.loader,
            'css-loader', // css-loader 用来解析@import这种语法,
            'postcss-loader'
          ]
        }
      ]
    }

    五.处理less等

    npm i less-loader
    {
      test: /.less$/,   // less 处理
      // use: 'css-loader'
      // use: ['style-loader', 'css-loader'],
      use: [
        // {
        //     loader: 'style-loader',
        //     options: {
        //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
        //     }
        // },
        MiniCssExtractPlugin.loader,   // 这样相当于抽离成一个css文件, 如果希望抽离成分别不同的css, 需要再引入MiniCssExtractPlugin,再配置
        'css-loader', // css-loader 用来解析@import这种语法
        'postcss-loader',
        'less-loader' // less-loader less -> css
        // sass node-sass sass-loader
        // stylus stylus-loader
      ]
    }

    less-loader

    六.抽离css文件,通过link引入

    yarn add mini-css-extract-plugin -D
    let MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
    // 压缩css
    
    plugins: [
      new MiniCssExtractPlugin({
          filename: 'css/main.css'
      })
    ]
    
    {
      test: /.css$/,   // css 处理
      // use: 'css-loader'
      // use: ['style-loader', 'css-loader'],
      use: [
        // {
        //     loader: 'style-loader',
        //     options: {
        //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
        //     }
        // },
        // 此时不需要style-loader
        MiniCssExtractPlugin.loader,   // 抽离
        'css-loader', // css-loader 用来解析@import这种语法,
        'postcss-loader'
      ]
    }

     mini-css-extract-plugin

    1.压缩css和js

    // 用了`mini-css-extract-plugin`抽离css为link需使用`optimize-css-assets-webpack-plugin`进行压缩css,使用此方法压缩了css需要`uglifyjs-webpack-plugin`压缩js
    const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
    const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
    
    module.exports = {
      optimization: {              // 优化项
        minimizer: [
          new UglifyJsPlugin({     // 优化js
            cache: true,           // 是否缓存
            parallel: true,        // 是否并发打包
            // sourceMap: true     // 源码映射 set to true if you want JS source maps
          }),
          new OptimizeCSSAssetsPlugin({})    // css 的优化
        ]
      },
      mode: 'production',
      entry: '',
      output: {},
    }

    七.给css加上兼容浏览器的前缀

    yarn add postcss-loader autoprefixer -D
    // css
    {
      test: /.css$/,   // css 处理
      // use: 'css-loader'
      // use: ['style-loader', 'css-loader'],
      use: [
        // {
        //     loader: 'style-loader',
        //     options: {
        //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
        //     }
        // },
        MiniCssExtractPlugin.loader,
        'css-loader', // css-loader 用来解析@import这种语法,
        'postcss-loader'
      ]
    }
    // less
    {
      test: /.less$/,   // less 处理
      // use: 'css-loader'
      // use: ['style-loader', 'css-loader'],
      use: [
        // {
        //     loader: 'style-loader',
        //     options: {
        //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
        //     }
        // },
        MiniCssExtractPlugin.loader,   // 这样相当于抽离成一个css文件, 如果希望抽离成分别不同的css, 需要再引入MiniCssExtractPlugin,再配置
        'css-loader', // css-loader 用来解析@import这种语法
        'postcss-loader',
        'less-loader' // less-loader less -> css
        // sass node-sass sass-loader
        // stylus stylus-loader
      ]
    },

    postcss 需要配置文档 postcss.config.js

    postcss-loader

    module.exports = {
      plugins: [
        require('autoprefixer')
      ]
    }

    八.es6 转 es5

    npm i babel-loader @babel/core @babel/preset-env -D
    module.exports = {
      module: {
        rules: [
          {
            test: /.js$/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: [ //预设
                  '@babel/preset-env' 
                ],
                plugins:[
                  // 转es7的语法
                  ["@babel/plugin-proposal-decorators", { "legacy": true }],
                  ["@babel/plugin-proposal-class-properties", { "loose" : true }]
                ]
              }
            },
            exclude: /node_modules/
          }
        ]
      }
    }

    1.转es7的语法

    // 转class
    npm i @babel/plugin-proposal-class-properties -D
    
    // 转装饰器
    npm i @babel/plugin-proposal-decorators -D

    2.其他不兼容的高级语法

    使用 @babel/polyfill

    3.语法检查 eslint

    npm i eslint eslint-loader -S

    根目录添加 .eslintrc.json 配置文件

    module.exports = {
      module: {
        rules: [
          {
            test: /.js$/,
            use: {
              loader: 'eslint-loader',
              options: {
                enforce: 'pre'  // previous优先执行  post-普通loader之后执行
              }
            }
          },
          {
            test: /.js$/,      // mormal 普通的loader
            use: {
              loader: 'babel-loader',
              options: {
                presets: [ //预设
                  '@babel/preset-env' 
                ]
              }
            },
            exclude: /node_modules/
          }
        ]
      }
    }

    九.全局变量引入第三方库(jq)

    npm i jquery -S
    let webpack = require('webpack')
    
    new webpack.ProvidePlugin({
      $: 'jquery'
    })

    1.暴露全局

    npm i expose-loader -D 暴露全局的loader

    a. 

    可以在js中 

    import $ from 'expose-loader?$!jquery' // 全局暴露jquery为$符号 

    可以调用window.$

    b.

     也可在webpack.config.js 中配置 rules

    module.exports = {
      module: {
        rules: [
          {
            test: require.resolve('jquery'),
            use: 'expose-loader?$'
          }
        ]
      }
    }

    以后在.js文件中引入

    import $ from 'jquery'

    c.

    如何在每个模块中注入:

    let webpack = require('webpack')
    
    module.exports = {
      plugins: [
        new webpack.ProvidePlugin({
          $: 'jquery'
        })
      ]
    }
    
    之后代码内直接使用 $

    d.

    index.html中通过script标签引入jquery, 但是在js中,用import会重新打包jquery,如何避免

    从输出的bundle 中排除依赖

    module.exports = {
      externals: { // 告知webpack是外部引入的,不需要打包
        jquery: 'jQuery'
      }
    }

    此时在index.js上

    import $ from 'jquery'
    
    console.log($)

    十.webpack图片打包处理

    1.js中创建

    2.css中引入

    3.<img src="">

    yarn add file-loader -D 适合一二情况
    module.export={
      module: {
        rules: [
          {
            test: /.(png|jpg|gif)$/,
            use: 'file-loader'
          }
        ]
      }
    }

    默认会内部生成一张图片到build,生成图片的路径返回回来

    第一种情况: 图片地址要import引入,直接写图片的地址,会默认为字符串

    import logo from './logo.png'
    
    let image = new Image()
    image.src = logo
    document.body.appendChild(image)

    第二种情况: css-loader会将css里面的图片转为require的格式

    div {
      background: url("./logo.png");
    }

    第三种情况: 解析html中的image

    {
      test: /.html$/,
      use: 'html-withimg-loader'
    }
    yarn add html-withimg-loader -D

    4. 当图片小于多少,用base64

    yarn add url-loader -D  如果过大,才用file-loader
    {
      test: /.(png|jpg|gif)$/,
      // 当图片小于多少,用base64,否则用file-loader产生真实的图片
      use: {
        loader: 'url-loader',
        options: {
          limit: 200 * 1024,          // 小于200k变成base64
          // outputPath: '/img/',     // 打包后输出地址
          // publicPath: ''           // 给资源加上域名路径
        }
      }

    十一.打包文件分类和多页面

    1.图片

    {
      test: /.(png|jpg|gif)$/,
      // 当图片小于多少,用base64,否则用file-loader产生真实的图片
      use: {
        loader: 'url-loader',
        options: {
          limit: 1,  // 200k 200 * 1024
          outputPath: 'img/'   // 打包后输出地址 在dist/img
        }
      }
    },

    2.css

    plugins: [
      new MiniCssExtractPlugin({
        filename: 'css/main.css'
      }),
    ]

    3.希望输出的时候,给这些cssimg加上前缀,传到服务器也能访问

    output: {
      filename: 'bundle.[hash:8].js',   // hash: 8只显示8位
      path: path.resolve(__dirname, 'dist'),
      publicPath: 'http://www.mayufo.cn'  // 给静态资源统一加
    },

    4.打包多页应用

    // 多入口
    let path = require('path')
    let HtmlWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
      mode: 'development',
      entry: {
        home: './src/index.js',
        other: './src/other.js'
      },
      output: {
        filename: "[name].js",
        path: path.resolve(__dirname, 'dist2')
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './index.html',
          filename: 'home.html',
          chunks: ['home']
        }),
        new HtmlWebpackPlugin({
          template: './index.html',
          filename: 'other.html',
          chunks: ['other', 'home']   // other.html 里面有 other.js & home.js
        }),
      ]
    }

    十二 配置source-map

    module.exports = {
      devtool: 'source-map' // 增加映射文件调试源代码
    }

    1.源码映射 会标识错误的代码 打包后生成独立的文件 大而全 「source-map」

    2.不会陈胜单独的文件 但是可以显示行和列 「eval-source-map」

    3.不会产生列有行,产生单独的映射文件 「cheap-module-source-map」

    4.不会产生文件 集成在打包后的文件中 不会产生列有行 「cheap-module-eval-source-map」

    十三 watch 改完代表重新打包实体

    module.exports = {
      watch: true,
      watchOptions: {
        poll: 1000,              // 每秒监听1000次
        aggregateTimeout: 300,   // 防抖,当第一个文件更改,会在重新构建前增加延迟
        ignored: /node_modules/  // 对于某些系统,监听大量文件系统会导致大量的 CPU 或内存占用。这个选项可以排除一些巨大的文件夹,
      },
    }

    十四 webpack的其他三个小插件

    1.clean-webpack-plugin

    每次打包之前删掉dist目录 yarn add clean-webpack-plugin -D
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    
    module.exports = {
      output: {
        path: path.resolve(process.cwd(), 'dist'),
      },
      plugins: [
        new CleanWebpackPlugin('./dist')
      ]
    }

    2.copyWebpackPlugin

    一些静态资源也希望拷贝的dist中
    
    yarn add copy-webpack-plugin -D
    const CopyWebpackPlugin = require('copy-webpack-plugin')
    
    module.exports = {
      plugins: [
        new CopyWebpackPlugin([
          {from: 'doc', to: './'}
        ])
      ]
    }

    3.bannerPlugin内置模块

    版权声明
    const webpack = require('webpack');
    
    new webpack.BannerPlugin('hello world')
    // or
    new webpack.BannerPlugin({ banner: 'hello world'})

    十五 webpack解析resolve

    bootstrap为例

    npm install bootstrap  -D
    index.js
    
    import 'bootstrap/dist/css/bootstrap.css'

    报错

    ERROR in ./node_modules/bootstrap/dist/css/bootstrap.css 7:0
    Module parse failed: Unexpected token (7:0)
    You may need an appropriate loader to handle this file type.
    |  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
    |  */
    > :root {
    |   --blue: #007bff;
    |   --indigo: #6610f2;
     @ ./src/index.js 22:0-42
     @ multi (webpack)-dev-server/client?http://localhost:8081 ./src/index.js

    这是因为bootstrap 4.0的css引入了新的特性,CSS Variables

    安装 npm install postcss-custom-properties --save-dev

    配置webpack.config.js

    {
      test: /.css$/,
      use: ['style-loader', 'css-loader', {
        loader: 'postcss-loader',
        options: {
          plugins: (loader) => [
            require("postcss-custom-properties")
          ]
        }
      }]
    }

    但是每次引入都很长,如何优雅引入

    resolve: {
      // 在当前目录查找
      modules: [path.resolve('node_modules')],
      alias: {
          'bootstrapCss': 'bootstrap/dist/css/bootstrap.css'
      }
    },
    import 'bootstrapCss'  // 在node_modules查找

    省略扩展名

    resolve: {
      // 在当前目录查找
      modules: [path.resolve('node_modules')],
      // alias: {
      //   'bootstrapCss': 'bootstrap/dist/css/bootstrap.css'
      // },
      mainFields: ['style', 'main'],   // 先用bootstrap中在package中的style,没有在用main
      // mainFiles: []  // 入口文件的名字 默认index
      extensions: ['.js', '.css', '.json']  // 当没有拓展命的时候,先默认js、次之css、再次之json
    },

    定义环境变量

    DefinePlugin 允许创建一个在编译时可以配置的全局常量。这可能会对开发模式和生产模式的构建允许不同的行为非常有用。

    let url = ''
    if (DEV === 'dev') {
      // 开发环境
      url = 'http://localhost:3000'
    } else {
      // 生成环境
      url = 'http://www.mayufo.cn'
    }

    webpack.config.js

    new webpack.DefinePlugin({
      // DEV: '"production"',
      DEV: JSON.stringify('production'),
      FLAG: 'true',   // 布尔
      EXPRESSION: '1 + 1'   // 字符串 如果希望是字符串 JSON.stringify('1 + 1')
    })

    区分两个不同的环境

    分别配置不同的环境

    webpack.base4.js 基础配置

    webpack.dev4.js 开发环境

    webpack.prod4.js 生产环境

    yarn add webpack-merge -D
    
    npm run build -- -- config webpack.dev4.js npm run build -- -- config webpack.build.js

    官方文档

    webpack.base4.js
    let path = require('path')
    let HtmlWebpackPlugin = require('html-webpack-plugin')
    let CleanWebpackPlugin = require('clean-webpack-plugin')
    
    module.exports = {
      entry: {
        home: './src/index.js'
      },
      output: {
        filename: "[name].js",
        path: path.resolve(process.cwd(), 'dist3')
      },
      module: {
        rules: [
          {
            test: /.js$/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: [
                  '@babel/preset-env'
                ]
              }
            }
          },
          {
            test: /.css$/,
            use: ['style-loader', 'css-loader', {
              loader: 'postcss-loader',
              options: {
                plugins: (loader) => [
                  require("postcss-custom-properties")
                ]
              }
            }]
          }
        ]
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html',
          filename: 'index.html'
        })
      ]
    }
    webpack.dev4.js
    let merge = require('webpack-merge')
    let base = require('./webpack.base4.js')
    
    module.exports = merge(base, {
      mode: 'development',
      devServer: {},
      devtool: 'source-map'
    })
    webpack.prod4.js
    let merge = require('webpack-merge')
    let base = require('./webpack.base4.js')
    
    module.exports = merge(base, {
      mode: 'production'
    })
    package.json
    "scripts": {
      "build": "webpack  --config webpack.prod4.js",
      "dev": "webpack-dev-server --config webpack.dev4.js"
    },

    十六 多线程打包happypack

    yarn add happypack
    let Happypack = require('happypack')
    
    
    rules: [
      {
        test: /.js$/,
        exclude: '/node_modules/',
        include: path.resolve('src'),
        use: 'happypack/loader?id=js'
      },
    ]
    
    plugins: [
      new Happypack({
        id: 'js',
        use: [{
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react'
            ]
          }
        }]
      })
    ]

    js启用多线程,由于启用多线程也会浪费时间,因此当项目比较大的时候启用效果更好

    css启用多线程

    {
      test: /.css$/,
      use: 'happypack/loader?id=css'
    }
    
    new Happypack({
      id: 'css',
      use: ['style-loader', 'css-loader']
    }),

    十七 抽取公共代码

    1.抽离自有模块

    module.exports = {
      optimization: {
        splitChunks: {             // 分割代码块,针对多入口
          cacheGroups: {           // 缓存组
            common: {              // 公共模块
              minSize: 0,          // 大于多少抽离
              minChunks: 2,        // 使用多少次以上抽离抽离
              chunks: 'initial'    // 从什么地方开始, 从入口开始
            }
          }
        }
      },
    }

    SplitChunksPlugin

    2.抽离第三方模块

    optimization: {
      splitChunks: {              // 分割代码块,针对多入口
        cacheGroups: {            // 缓存组
          common: {               // 公共模块
            minSize: 0,           // 大于多少抽离
            minChunks: 2,         // 使用多少次以上抽离抽离
            chunks: 'initial'     // 从什么地方开始,刚开始
          },
          vendor: {
            priority: 1,          // 增加权重, (先抽离第三方)
            test: /node_modules/, // 把此目录下的抽离
            minSize: 0,           // 大于多少抽离
            minChunks: 2,         // 使用多少次以上抽离抽离
            chunks: 'initial'     // 从什么地方开始,刚开始
          }
        }
      },
    },

    十八 懒加载(延迟加载)

    yarn add @babel/plugin-syntax-dynamic-import -D
    source.js
    export default 'mayufo'
    index.js
    let button = document.createElement('button')
    button.innerHTML = 'hello'
    button.addEventListener('click', function () {
      console.log('click')
      // es6草案中的语法,jsonp实现动态加载文件
      import('./source.js').then(data => {
        console.log(data.default)
      })
    })
    document.body.appendChild(button)
    {
      test: /.js$/,
      exclude: '/node_modules/',
      include: path.resolve('src'),
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [
            '@babel/preset-env',
            '@babel/preset-react'
          ],
          plugins: [
            '@babel/plugin-syntax-dynamic-import'
          ]
        }
      }]
    }

    十九 热更新(当页面改变只更新改变的部分,不重新打包)

    plugins: [
      new HtmlWebpackPlugin({
        template: './src/index.html',
        filename: 'index.html'
      }),
      new webpack.NameModulesPlugin(),          // 打印更新的模块路径
      new webpack.HotModuleReplacementPlugin()  // 热更新插件
    ]
    index.js
    import str from './source'
    
    console.log(str);
    
    if (module.hot) {
      module.hot.accept('./source', () => {
        console.log('文件更新了');
        require('./source')
        console.log(str);
      })
    }
  • 相关阅读:
    View 和 ViewGroup 的 hasFocusable
    tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断【转】
    tiny4412学习(三)之移植linux-4.x驱动(1)支持网卡驱动【转】
    分享tiny4412,emmc烧录u-boot, 支持fastboot模式烧写emmc【转】
    tiny4412学习(一)之从零搭建linux系统(烧写uboot、内核进emmc+uboot启动内核)【转】
    【总结】嵌入式linux内核中Makefile、Kconfig、.config的关系及增加开机Hello World【转】
    tiny4412 裸机程序 九、串口排查驱动原因及字符图片显示【转】
    tiny4412 裸机程序 八、重定位到DRAM及LCD实验【转】
    tiny4412 裸机程序 七、重定位代码到DRAM【转】
    tiny4412 裸机程序 六、重定位代码到IRAM+0x8000【转】
  • 原文地址:https://www.cnblogs.com/feifan1/p/12636942.html
Copyright © 2011-2022 走看看