webpack学习笔记

Webpack

webpack5原理与应用B站视频

此文章仅为webpack学习过程中的完整笔记。精粹笔记请见webpack学习之代码分析

为什么需要webpack?

不使用webpack时:

其一,需要加载多个js文件。缺点:多个js之间的依赖关系需要按顺序进行引入,扩展性低,局限性大;

其二,只加载一个继承了所有js文件代码的js文件。缺点:作用域问题(不同js绑定不同的变量,如jquery的$和loadash),文件太大,可读性差,可维护性弱。

解决作用域问题(早期GRUNT,GULP):

IIFE(immediately invoke function expression)立即执行函数表达式

;(function(){var name=1;return name;})();
//即没让name污染环境,解决了作用域问题,又能访问到name;

如何代码拆分,只要加载需要用到的模块

//暴露模块
module.exports = {module1,module2};
//获取模块
const a = require('./modules');
//在获取的页面进行使用
a.module1;a.module2;

require只适用于NodeJs,浏览器无法使用;

浏览器如何支持模块(早期browserify,reqiure.js)

//引用require.js,提供define和require
//define:定义模块,且要return,能被其他模块引用;define([以来的地址 空],function(){return 当前js定义的函数模块add })

//require:定义模块,不需要return,但不能被其他js引用;require([依赖的地址],function(按依赖地址顺序导入的模块的形参add){ 当前js定义的函数模块 add(1,2)})
//多模块为一个js文件
add.js & minus.js:里面用define

现在的浏览器支持方式

//定义
const  add=(x,y)=>{return x+y}
export default add;
//载入
<script type="module">
//不配置type="module",会报错:不能再模块外不调用import
    import add from '地址'
    </script>

npx命令:当一个模块不存在时,会从网上先下载再执行

浏览器支持ECMAScript的模块不太好,且迭代太慢,所以要用webpack

webpack能干嘛

打包js应用程序,支持es的模块化和commomjs。扩展支持其他静态资源的打包,图片,字体,样式文件;

webpack竞品 Vite,Rollup,Parcel

如何解决作用域冲突(IIFE),如何代码拆分(模块化),如何让浏览器支持模块(require.js和es的模块化)

webpack应用

全局安装webpack(不推荐全局,会锁定某个版本;在团队协作在容易有差异。)

npm install webpack webpack-cli --global
//查看webpack版本
webpack -v

全新项目内安装webpack

npm init -y 使用默认配置生成

-y 的含义:yes的意思,在init的时候省去了敲回车的步骤,生成的默认的package.json

version 版本号,一般从0.1.0开始

description描述

keywords 关键词用逗号隔开

author名字加邮箱

license UNLICENSE,一般不授权公用
npm install webpack webpack-cli --save-dev
项目内安装‘开发’依赖
pwd 打印当前工作目录
//在项目文件夹内打包,此时的webpack时全局的webpack
webpack

//查看打包详情
webpack --status detailed

//使用项目内的webpack进行打包
①先卸载全局的webpack
npm uninstall webpack webpack-cli --global
②使用项目内的webpack进行打包
npx webpack //先在当亲目录找,没有就往上继续找

webpack.config.js配置

为什么用:命令行配置麻烦,且无法保存配置;

在项目目录下新建webpack.config.js。

运行时,webpack自动读取。

在nodejs中运行,使用了nodejs的commonjs模块,因此需要使用

const path = require('path')
module.exports = {
  entry: './src/index.js',
  mode: 'none',
  // "development" | "production" | "none"
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist')
    //path需要为绝对路径
  }
}

麻烦:每次都要去index.html里面更新打包后的js地址。

插件来源:

社区(htmlWebpackPlugin),

webpack内置,

第三方;

使用HtmlWebpackPlugin

mode选项

取值:none,development,production

使用sourceMap进行调试

#安装
npm install html-webpack-plugin -D (--save-dev)

目前预览项目效果是通过访问当前index.html的地址

入口文件及其依赖变化时,webpack自动进行打包,但还是要手动刷新页面;

npx webpack --watch

webpack热更新:使用webpack -dev-server进行页面的更新(重新加载);webpack --watch只是为了自动打包。

不监听webpack.config.js

//安装,作为开发依赖进行安装到本地
npm install webpack-dev-server -D
#原理:不依赖dist内的文件。没有输出任何物理文件,将最新的打包后的文件放在内存中,且指定的内存文件夹的名字由devServer.static指定,文件发生变化后,立即在内存生成一份最新的,并提供使用;
删除dist后,无发访问dist文件夹,但还是能访问到内部的html文件;

资源模块asset module(webpack内置资源模块):允许使用webpack来打包其他资源文件。字体,图片,样式等。

资源模块类型asset module type:通过四种资源模块类型来替换所有loader

asset/resource:发送单独文件并导出url(生成文件)

asset/inline:导出资源的URI (不生成文件,生成dataURI并填入要用的地方)

asset/source :导出资源的源代码(不生成文件)

asset:选择发送单独文件(resource)还是导出资源的URI(inline)

#自动运行webpack-dev-server之后打开网页
npx webpack-dev-server --open

Loader

什么是Loader:webpack只能理解js和json这样的文件;loader可以让webpack解析其它类型的文件。

使用loader加载css代码

#安装css-loader
npm install css-loader -D
//导入并使用style.css
import './style.css'

document.body.classList.add('hello')

抽离和压缩css

#安装抽离CSS插件
npm install mini-css-extrace-plugin -D
#安装压缩CSS插件
npm install css-minimizer-webpack-plugin
#webpack5版本才可以用

加载字体

//加载字体:需要为字体格式后缀的文件,用module.rule处理,type为'asset/resource'
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      type: 'asset/resource'
    }
//不需要额外的loader,是因为字体是被css文件引用的,因此会被编入到css文件内,而css文件又有css-loader进行处理。

加载数据

CSV,TSV

#安装依赖
npm install csv-loader
npm install xml-loader

babel -loader

为什么需要babel-loader:将ES6->ES5,将es6转换成低版本浏览器能够运行的es5

#安装三个包 
babel-loader:webpack里应用babel解析ES6的桥梁
@babel/core:babel核心模块
@babel/preset-env:babel的预设,一组babel插件的集合

npm install babel-loader @babel/core @babel/preset-env -D

缺少regeneratorruntime插件

#下载插件

#regeneratorruntime运行时需要的内容
npm install @babel/runtime -D
#在需要regeneratorruntime的地方自动导包。
npm install @babel/plugin-transform-runtime -D

代码分离(抽离重复代码;加快首屏加载;)

入口起点:使用entry配置手动地分离代码;共用的文件会被重复打包

防止重复:使用Entry dependencies或者splitChunksPlugin(抽离静态代码import…from…关键字)去重和分离代码

动态导入:通过模块的内联函数(import)来分离代码;可以进行懒加载(用到再加载);

const btn = document.createElement('button')
btn.textContent = '点击运行'
btn.addEventListener('click', () => {
  import('./math.js').then(({ add }) => {
    console.log(add(1, 2))
  })
})
document.body.appendChild(btn);

splitChunksPlugin和动态导入(import方法导入模块)一起使用实现动静态代码抽离

实践:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3HwEo50-1643037187254)(C:\Users\a1808\AppData\Roaming\Typora\typora-user-images\image-20220115020617736.png)]

魔法注释(动态分离)

为用import(‘…’)方法引入的模块,进行分包时命名。

//正常,以lodash的地址进行命名
import('lodash').then(({add})->{})
//魔法注释,剥离出来的包就叫math11
import(/*webpackChunkName:'math11'*/'lodash').then(({add})->{})

预加载(使用魔法注释配置webpackPrefetch:true;)

//魔法注释,剥离出来的包就叫math11
import(/*webpackChunkName:'math11',webpackPreload:true */'lodash').then(({add})=>{})

预获取:如若配置webpackPreload:true,则效果类似懒加载;

通过link标签来引入资源到index.html(再所有资源加载完成后,网络空闲时,进行加载)

下图为预获取

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOapQ8ZD-1643037187256)(C:\Users\a1808\AppData\Roaming\Typora\typora-user-images\image-20220116015350259.png)]

//魔法注释,剥离出来的包就叫math11
import(/*webpackChunkName:'math11',webpackPrefetch:true */'lodash').then(({add})=>{})
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CSSMinimizerWenpackPlugin = require('css-minimizer-webpack-plugin')
const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')

const path = require('path')
module.exports = {
  // 要打包的文件,单入口
  // entry: './src/index.js',
  // 多入口,对象;使用splitChunksPlugin进行分离需要搭配optimization.splitChunks:{chunks:'all'}
  entry: {
    index: './src/index.js',
    another: './src/another-module.js'
  },
  // 多入口,防止重复
  // entry: {
  //   index: {
  //     import: './src/index.js',
  //     dependOn: "shared"
  //   },
  //   another: {
  //     import: './src/another-module.js',
  //     dependOn: "shared"
  //   },
  //   // 共同模块的入口,也会呗putput输出;如果上面的包含dependOn的入口如果有引入lodash这个模块。那么就把'lodash'取名为‘shared’,供多个入口使用;
  //   shared: 'lodash'
  // },
  //打包后的文件放哪里
  output: {
    // 单入口的entry配置的文件名
    // filename: 'bundle.js',
    // 多入口
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, './dist'),
    //清空dist内的文件再生成
    clean: true,
    //指定资源的文件名
    // assetModuleFilename: 'images/test.png'
    assetModuleFilename: 'images/[contenthash][ext]'
  },
  // mode: 'production', 
  mode: 'development',
  //定位错误到开发文件。而不是打包后的代码;
  devtool: 'inline-source-map',
  // "development" | "production" | "none"
  // 插件(社区,内置,)
  plugins: [
    new HtmlWebpackPlugin({
      // 要使用当作模板的文件地址
      template: './index.html',
      // 生成后的文件名
      filename: 'app.html',
      // 将打包后的bundle.js插入到body元素内
      inject: 'body'
    }),
    new MiniCssExtractPlugin({
      // 生成后的文件名
      filename: 'style/mystyle.css',
    })
    // 生成html,且自动引入打包生成的bundle.js;如果不配置构造对象那么就生成默认的index.html,无自定内容,且打包后的js默认放在head里面;
  ],
  // 供webpack-dev-server进行配置
  devServer: {
    //文件夹就打开目录,为文件就打开文件;先打开文件夹再开目录可以看;直接打开文件就不行;
    static: './dist',
    open: true
  },

  module: {
    rules: [{
      test: /\.png$/,
      type: 'asset/resource',
      //具体定制生成后的文件名,优先级别比output内的assetModuleFilename高
      generator: {
        // filename: 'images/generator1.png'
      }
    },
    {
      test: /\.jpg$/,
      type: 'asset/inline'
    },
    {
      test: /\.txt$/,
      // 生成打他URI,base64的格式
      type: 'asset/source'
    }, {
      test: /\.jpeg$/,
      // 选择导出文件并返回url,或者是生成uri
      type: 'asset',
      parser: {
        //设置判断资源的大小,单位KB
        dataUrlCondition:
          { maxSize: 4 * 1024 * 1024 }
      }
    },
    // {
    //   test: /.css$/,
    //   use: 'css-loader'
    //   },
    // {
    //   test: /\.css$/,
    //   use: ['style-loader', 'css-loader']
    //   //解析成功,但是未被页面引入
    // },
    // {
    //   test: /\.(css|scss)$/,
    //   use: ['style-loader', 'css-loader', 'sass-loader']
    // },
    {
      test: /\.(css|scss)$/,
      use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
    },
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      type: 'asset/resource'
    },
    {
      test: /\.(csv|tsv)$/,
      use: 'csv-loader'
    },
    {
      test: /\.xml$/,
      use: 'xml-loader'
    },
    {
      test: /\.toml$/,
      type: 'json',
      parser: {
        parse: toml.parse
      }
    },
    {
      test: /\.yaml$/,
      type: 'json',
      parser: {
        parse: yaml.parse
      }
    },
    {
      test: /\.json5$/,
      type: 'json',
      parser: {
        parse: json5.parse
      }
    },
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: [
            [
              '@babel/plugin-transform-runtime'
            ]
          ]
        }
      }
    }
    ]
  },
  optimization: {
    minimizer: [
      // 需要将mode改为production(只在生产环境进行压缩)
      new CSSMinimizerWenpackPlugin()
    ],
    // 多入口时,处理共同代码。共同的模块生成n个(vendors- 模块的文件地址) 开头的js文件,这些模块由import ...from..进行引入,都是静态资源;
    // splitChunks: {
    //   chunks: 'all'
    // }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值