webpack 学习记录

webpack-前端资源构建工具,静态资源打包器(moudle bundler)

1 学习目标
  • 知道webpack是干嘛的,核心组成
  • webpack的主要配置文件
  • webpack处理图片,css预编译语言,vue文件
  • 使用空文件夹构建一个vue工程
  • 了解webpack优化思路
2 资源构建工具/打包器是什么
  • 处理js es6 -> es5 babel
  • 处理css less/scss -> css loader
  • 处理png、jpg。。。-> url-loader file-loader
  • 一个大的工具来处理这些 —> webpack
3 webpack 五大核心 官网文档
  • entry -> 入口起点(entry point) 指示 webpack 应该使用哪个模块

  • output -> output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。

  • loader -> webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。

  • plugin -> loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

    Tip

  • mode -> 通过选择 development, productionnone 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production

    npm i webpack webpack-cli
    
4 处理es6
npm install --save-dev babel-loader @babel/core  @babel/cli @babel/preset-env

// .babelrc

{
  "presets": [
    "@babel/preset-env"
  ]
}

// webpack.config.js 添加loader

{
        //  正则表达式匹配js文件
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
          },
        ],
},
5 处理css ,less,scss,sass
npm i less-loader css-loader style-loader sass-loader
6 处理图片 jpg,png,gif。。。
npm i url-loader file-loader html-loader
7 html-webpack-plugin插件打包资源放入html中
npm i html-webpack-plugin
  • 不配置任何选项的html-webpack-plugin插件,他会默认将webpack中的entry配置所有入口thunk和extract-text-webpack-plugin抽取的css样式都插入到文件指定的位置。例如上面生成的html文件内容如下:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>Webpack App</title>
      <link href="index-af150e90583a89775c77.css" rel="stylesheet"></head>
      <body>
      <script type="text/javascript" src="common-26a14e7d42a7c7bbc4c2.js"></script>
      <script type="text/javascript" src="index-af150e90583a89775c77.js"></script></body>
    </html>
    
  • 配置自己的模板

      plugins: [
        // 详细plugins的配置
        new HtmlWebpackPlugin({
          filename: 'index.html',
          template: 'index.html'
        })
      ],
    
8 写一个vue文件打包
npm i vue-loader vue-template-compiler @vue/compiler-sfc
// v15.*以上需要配置webpack的插件npm i vue-loader-plugin
   "vue-loader": "^15.7.0",
   // 和vue版本一致
   "vue-template-compiler": "^2.6.14",
    "webpack": "^5.4.0",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.2"
// webpack配置文件中添加
const VueLoaderPlugin = require('vue-loader-plugin');
  // plugins的配置
  plugins: [
    // 详细plugins的配置
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html'
    }),
    new VueLoaderPlugin()
  ],
// npm 报错处理
npm i --legacy-peer-deps
    rules: [
      // 详细loader配置
      // 不同文件必须配置不同loader处理
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        exclude:/node_modules/
      },
      ]
  • 文件夹部署vue注意事项

    • 每个包之间的版本过高会报错
    "vue-loader": "^15.7.0",
    "vue": "^2.6.14",
    "vue-template-compiler": "^2.6.14",
    "webpack": "^5.4.0",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.2"
    "css-loader": "^5.2.7",
    "html-webpack-plugin": "^5.3.2",
    "scss": "^0.2.4",
    "url-loader": "^4.1.1",
    "scss-loader": "^0.0.1",
    "style-loader": "^3.1.0",
    "postcss-loader": "^6.1.1",
    "vue-loader-plugin": "^1.3.0"
    "@vue/compiler-sfc": "^3.1.4",
    "file-loader": "^6.2.0",
    "html-loader": "^2.1.2",
    
    • vue-loader v15.** 之后需要添加webpack插件解析vue文件
      npm i vue-loader-plugin
      const VueLoaderPlugin = require('vue-loader-plugin');
      plugins: [
        // 详细plugins的配置
        new HtmlWebpackPlugin({
          filename: 'index.html',
          template: 'index.html'
        }),
        new VueLoaderPlugin()
      ],
    
9 将css 提取成单独的css文件
npm 下载插件
npm i mini-css-extract-plugin -D
// 配置plugin
// 插件配置
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
new MiniCssExtractPlugin({
    //输出文件夹和文件名
    filename:'static/css/built.css'
}),
// loader配置
{
    // 匹配哪些文件
    test: /\.css$/,
    // 使用哪些loader进行处理
    use: [
    MiniCssExtractPlugin.loader,
    'css-loader',
    ]
},
10 手写一个Loader
  • Loader实际上就是一个函数 入参source

    module.exports= function(source) {
        // console.log(source)
        return source.replace(/我/g, '小明');
    }
    
11 手写一个plugin插件 官网
  • plugin 生命周期 官方文档

  • 手写一个HelloPlugin

    • 一个具名javascrpit函数
    • 在插件函数的prototype上定义一个apply方法
    • 指定一个绑定到webpack自身的事件钩子
    • chuliwebpack内部实力的特定数据
    • 功能完成后调用webpack提供的回调
    class HelloPlugin {
        constructor(options) {
            this.options = options
        }
        apply(compiler){
            compiler.hooks.afterEmit.tap('HelloPlugin',compilation => {
           		 console.log('hello');
            })
        }
    }
    module.exports = HelloPlugin
    
  • Compiler和Compilation

    compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境.

    compilation 对象代表了一次资源版本构建。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。

  • 手写一个HTMLWebpackPlugin

    // html解析html
    npm i cheerio
    
    const cheerio = require('cheerio');
    const fs = require('fs');
    
    class HTMLPlugin {
        constructor(options) {
            this.options = options
        }
        apply(compiler){
            compiler.hooks.afterEmit.tap('HTMLPlugin',compilation => {
            // console.log(compilation.assets)
            let result = fs.readFileSync(this.options.template, 'utf-8');
            let $= cheerio.load(result);
            // Object.keys(compilation.assets)
            Object.keys(compilation.assets).forEach(item => {
                if(/\.js$/.test(item)) {
                    $(`<script src="./${item}"></script>`).appendTo('body');
                }
                if(/\.css$/.test(item)) {
                    $(`<link href="./${item}" rel="stylesheet">`).appendTo('head');
                }
            })
            // console.log($.html());
            fs.writeFileSync('./dist/'+this.options.filename,$.html())
            })
        }
    }
    module.exports = HTMLPlugin
    
12 webpack 优化
12.1 production模式打包自带优化
  • tree shaking

    打包时移除未引用代码dead-code,它依赖于ES6模块系统中的import和export

  • scope hoisting

    将模块之间的关系进行结果推测,把打散的模块合并到一个函数。可以让webpack打包出来的代码文件更小,运行更快

  • 代码压缩

    所有代码使用UglifyjsPlugin插件进行压缩

12.2 css提取到单独文件 mini-css-extract-plugin ctrl+click见上文
12.3 postcss-loader autoprefixer添加代码前缀 文档
npm install --save-dev postcss-loader postcss-preset-env autoprefixer

// postcss.config.js

const autoprefixer = require('autoprefixer')({overrideBrowserslist: ['> 0.15% in CN']});
module.exports = {
    plugins: [autoprefixer]
}
12.4 分析包的内容 插件webpack-bundle-analyzer 官方文档
npm install webpack-bundle-analyzer --save-dev
// 添加插件
// 分析包内容
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: [
    // 开启 BundleAnalyzerPlugin
    new BundleAnalyzerPlugin({
    	// 默认打开 端口号8000
    	// 设置为disabled 需要设置script脚本 "bundle-report": "webpack-bundle-analyzer --port 8123 dist/stats.json"
         analyzerMode: 'server',
         generateStatsFile: true,
         statsOptions: {source: false}
    }),
  ],
};
12.5 多入口打包,js优化,Code Spliting增加首屏响应速度
  • 抽取公共代码 webpack4+ --> splitChunksPlugin插件—webpack 内置插件 官网

    module.exports = {
        optimization: {
            splitChunks: {
                chunks: 'all'
            }
        }
    }
    
12.6 js 动态导入
  • webpack4+ 允许import语法动态导入,需要babel的插件支持 @babel/plugin-syntax-dynamic-import

    npm i -D @babel/plugin-syntax-dynamic-import
    
    • 修改.babelrc配置文件,添加插件,低版本浏览器需要添加es6.promis官方文档

      {
      "presets": ["@babel/env"],
      "plugins": [
      	"@babel/plugin-syntax-dynamic-import"
      ]
      }
      
    • 静态导入 import 需要把import放到顶级作用域

      import $ from 'juqery'
      
    • 动态导入import写法

      let a=1;
      if(a===1) {
          import('jquery').then(({ default: $ })=> {
          	// TODO:
          })
      }
      
12.7 提高构建性能
  • noParse 官网

    防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。

    例如引入一些第三方库时,比如jquery, bootstrap,其内部不会有其他模块的依赖。配置noParse跳过解析依 赖。

    module: {
    noParse: /jquery|bootstrap/,
    rules: [
        {
            test: /\.js/,
            use: {},
            exclude: /node_modules/, //配置不包含哪些文件夹,loader会跳过这些文件夹
            include: path.resolve(__dirname, 'src'), // 包含哪些文件夹,loader会从这些文件夹里解析
        }
    ]
    }
    
  • IgnorePlugin 官网

    IgnorePlugin 阻止为匹配正则表达式或过滤器函数的模块生成importrequire调用。

    在引入一些第三方模块时,例如moment,内部会做i18n国际化处理,所以会包含很多语言包,比较占空间,例如如果只用中文语言包,可以忽略所有的语言包,按需引入语言包,从而使构建效率更高,打包生成文件更小

    • 首先找到moment所依赖的语言包是什么

      import moment from 'moment'
      // 手动引用语言包
      import 'moment/locale/zh-cn'
      // 设置语言国际化
      moment.locale('zh-CN')
      console.log(moment().subtract(6,'days').calendar())
      
    • 使用IgnorePlugin忽略其依赖

      new webpack.IgnorePlugin({
        resourceRegExp: /^\.\/locale$/,
        contextRegExp: /moment$/,
      });
      
    • 需要使用某些依赖时手动引入

  • DllPlugin 官网

    DllPluginDllReferencePlugin 用某种方法实现了拆分 bundles,同时还大幅度提升了构建的速度。“DLL” 一词代表微软最初引入的动态链接库。

    此插件用于在单独的 webpack 配置中创建一个 dll-only-bundle。 此插件会生成一个名为 manifest.json 的文件,这个文件是用于让 DllReferencePlugin 能够映射到相应的依赖上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值