Webpack4那点事

知识点扫盲

构建

  • 概念:把源代码转换成发布线上可执行的jscsshtml代码的过程
  • 特色:
    • 1.代码转换(ts—>jsless/scss—>css等)
    • 2.文件优化(压缩jscsshtml代码;压缩合并图片等)
    • 3.代码分割(提取多个页面的公共代码,提取首屏不须要执行部分的代码让其异步加载)
    • 4.模块合并(把多个模块文件分类合并成一个文件)
    • 5.自动刷新(在开发过程当中监听本地源代码的变化,自动从新构建、刷新浏览器)
    • 6.代码校验(在代码被提交到仓库以前须要校验代码是否符合规范,以及单元测试是否经过)
    • 7.自动发布(更新完代码后,自动构建出线上发布代码并传输给发布系统)

怎么用

注:若是你是初学者,但愿你能跟着个人步骤操做一下css

安装

  • 一、为了版本一直咱们推荐使用本地安装(npm install webpack --save-dev)
  • 二、安装webpack-cli(npm install webpack-cli --save-dev),以便解析用户传参(核心yargs)

零配置打包

文件目录建立

  • 根目录建立src文件夹并在其中建立index.js文件
// index.js
console.log('hello webpack')
复制代码

简单实现一(入口无依赖文件)

  • 运行npx webpack
    • 此时发现,根目录下会出现一个包含main.js文件的dist文件夹;同时你也必定注意到了如上图中红框所圈出的WARNING,是由于咱们没有指定mode(模式:包含生产(production)和开发(development)两种),不传会默认production模式
  • 运行npx webpack --mode development
    • 此时不会出现上图中的WARNING,比较一下此时main.js和以前的区别

简单实现二(入口有依赖文件)

  • src文件夹中再建立一个other.js,在index.js经过require引入
// other.js
module.exports = 'hello webpack'

// index.js 
const other = require('./other.js')
console.log(other)
复制代码
  • 运行npx webpack --mode development
  • 在生成的dist文件夹下建立一个index.html文件并引入产生的main.js文件,在浏览器中查看index.htmlconsole
  • 再尝试一下在index.html中直接引入src文件夹下的index.js,在浏览器中查看index.htmlconsole

后者的缘由是由于咱们的浏览器不支持coomonjs,这里我不作过多解释;咱们来分析一下前者是如何实现的html

// 删除掉冗余部分的main.js文件
(function (modules) {
  var installedModules = {};
  function __webpack_require__(moduleId) { // ./src/index.js ./src/other.js
    if (installedModules[moduleId]) { // 相似Commonjs中的缓存处理
      return installedModules[moduleId].exports;
    }
    var module = installedModules[moduleId] = {
      i: moduleId,
      l: false,
      exports: {}
    };
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    module.l = true;
    return module.exports;
  }
  return __webpack_require__("./src/index.js");
})
  ({
    "./src/index.js":
      (function (module, exports, __webpack_require__) {
       // 默认会调用 require("./src/other.js")
        eval("const other = __webpack_require__(\"./src/other.js\");console.log(other);");
    
      }),
    "./src/other.js":
      (function (module, exports) {
        eval("module.exports = 'hello webpack';");
      })
  });
  /* webpack打包流程 * 1.找到入口文件(index.js) * 2.找到入口文件中的依赖模块(other.js) ast解析加载依赖模块 * 3.从入口文件开始执行 require方法改写成 __webpack_require__ * 内部本身实现了一个Commonjs模块(须要找到入口,须要找到入口中的全部依赖,加载依赖 + 模板——>渲染后的结果) */
复制代码

增长配置打包

真正的开发中咱们确定不会零配置打包,确定根据咱们的须要来手动配置webpacknode

配置入口文件

  • 在全局建立webpack.config.jswebpackfile.js文件。(本文以webpack.config.js为例)
  • 编辑webpack.config.js(采用coomonjs规范)
// webpack.config.js
module.exports = { // 导出一个对象;对象中放置配置;会调用这个配置进行构建
}
复制代码
  • 修改src文件夹下index.js文件名为guYan.js,执行npx webpack --mode development,报错显示找不到入口文件
  • webpack.config.js文件中增长入口的位置,并执行npx webpack --mode development;无报错
// webpack.config.js
module.exports = {
    entry: './src/guYan.js' //当前入口文件的位置
}
复制代码

注:咱们能够经过执行npx webpack --mode development时增长config参数来实现修改默认配置文件webpack.config.js的名字。好比咱们如今修改webpack.config.js文件名为webpack.guYan.js而后执行npx webpack --mode development --config webpack.guYan.js效果和以前同样react

配置出口文件

  • webpack.config.js文件中增长出口文件的配置,并执行npx webpack --mode development,效果如图
// webpack.config.js
const path = require('path');
module.export = {
    entry: './src/guYan.js',
    output:{ // 配置当前出口文件
        filename: 'bundle.js',  // 出口文件名
        path: path.resolve(__dirname,'./build') // 出口目录,该配置项必须是绝对路径,默认dist目录
    }
}
复制代码

配置HTML模板

  • 在根目录建立public目录,并在其中建立index.html文件
  • 下载html-webpack-plugin插件(npm install html-webpack-plugin --save-dev)
    • 做用:根据模板产生一个打包后的html
  • webpack.config.js文件中增长HTML模板的配置(使用html-webpack-plugin插件)
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 1.引入插件
module.exports = {
    entry:'./src/guYan.js',
    output:{
        filename:'bundle.js',
        path:path.resolve(__dirname,'./build')
    },
    plugins:[ // 2.在plugins中注册插件
        new HtmlWebpackPlugin({
            template:'./public/index.html', // 指定模板
            filename:'gy.html' // 指定打包后的文件名,默认为index.html
        })
    ]
}
复制代码
  • 执行npx webpack --mode development,输出文件目录如图,而且你会发如今输出的gy.html中自动引入了打包后的bundle.js
  • 上述虽然已经完成了动态引入,可是执行npx webpack --mode production会发现打包后的bundle.js被压缩,可是gy.html没有被压缩,还有就是引用的文件一直是一个咱们不清楚会不会出现缓存的问题,这上线确定是不容许的啊,因此咱们须要继续配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.export = {
    entry:'./src/guYan.js',
    output:{
        filename:'bundle.js',
        path:path.resolve(__dirname,'./build')
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename:'gy.html',
            minify:{ // 配置压缩形式
                removeAttributeQuotes: true, // 删除全部属性的引号
                collapseWhitespace: true // 删除全部空白
            },
            hash:true // 每次引用js文件都加入哈希戳
        })
    ]
}
复制代码
  • 执行npx webpack --mode production后对比以前的效果查看

配置mode(模式)

  • 上文中咱们执行打包命令的时候都会传一个mode参数,其实没有必要这么麻烦,咱们能够在webpack.config.js中配置mode;执行npx webpack结果和上文同样
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports= {
    mode: 'production', // 默认两个参数 development production
    entry: './src/guYan.js',
    ...
}
复制代码

配置clean-webpack-plugin(清理文件夹)

在开发构建的过程当中咱们更但愿在打包后的文件夹中一直是最新的打包文件,即先删除掉以前打包产生的文件夹及文件webpack

  • 安装clean-webpack-plugin(npm install clean-webpack-plugin --save-dev)
  • webpack.config.js文件中进行配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clearn-webpack-plugin'); // 1.引入插件
module.exports = {
    mode:'development',
    entry: './src/guYan.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname,'./build')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'gy.html',
            minify: {
                removeAttributeQuotes: true,
                collapseWhitespace: true
            },
            hash:true
        }),
        /*清空文件的插件*/
        new CleanWebpackPlugin({ // 2.注册插件
            cleanOnceBeforeBuildPatterns:['**/*'], // 匹配目录下的全部文件清空,默认也是全部
        })
    ]
}
复制代码

配置多入口打包

  • 上述示例中全部webpack.config.js中的entry的值都是一个路径字符串的格式('./src/guYan.js'),当咱们的入口只有一个的时候咱们这样写ok,可是当咱们须要同时打包多个文件的时候呢?咱们如何处理呢?对的,它的值还能够是个对象
  • 首先咱们准备再准备一个入口文件guYan2.js
// src/guYan2.js
console.log('I am GuYan');
复制代码
  • webpack.config.js中修改咱们的配置,并执行npx webpack打包后的文件夹变化效果
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    mode:'development',
    entry:{ // 配置多入口
        index:'./src/guYan.js',
        other:'./src/guYan2.js'
    },
    output:{ 
        filename: '[name].js',// 为了响应多入口出口文件名须要动态建立,保证每一个入口都有输出
        path: path.resolve(__dirname,'./bundle')
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./public/index.html',
            filename:'index.html',
            minify:{
                removeAttributeQuotes:true,
                collapseWhitespace:true
            },
            hash:true
        }),
        new CleanWebpackPlugin({
            clearnOnceBeforeBuildPatterns:['**/*']
        })
    ]
}
复制代码

  • 在上文中咱们为了打包后的html文件引入打包后的js文件不出现缓存给咱们形成的困扰,咱们在使用html-webpack-plugin的时候配了一个hash,咱们也能够在出口文件名的位置加入[contentHash]参数
// webpack.config.js
...
output:{
    filenama:'[name].[contentHash:8].js' // :后面的是表明长度
}
...
复制代码

  • 上文打包以后咱们发现如今打包出两个js文件一个html文件中引用了两个js文件,那若是咱们想分别引用呢?怎么处理?对的,再new一次html-webpack-plugin。因此咱们写一个循环来处理一个plugin须要屡次引用的问题
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let htmlPlugins = ['index','other'].map(chunkName=>(new HtmlWebpackPlugin({
    filename:`${chunkName}.html`,
    chunks:[chunkName] // 保证按需引入 即index.html文件只引入index.js;other.html只引入other.js
})));
modeule.exports = {
    mode:'development',
    entry:{
        index:'./src/guYan.js',
        other:'./src/guYan2.js'
    },
    output:{
        filename:'[name].[contentHash:8].js',
        path:path.resolve(__dirname,'./build')
    },
    plugins:[
        new CleanWebpackPlugin(),
        ...htmlPlugins
    ]
}
复制代码

配置devServer(webpack-dev-server)

在开发过程当中咱们更但愿的是咱们一边修改代码页面自动更新,固然这种处理咱们有两种方案一个是经过编译的时候传入--watch不推荐使用(因此我就不作介绍了),另外一种就是经过webpack-dev-server来启动,这种方式不会产生构建好的文件,而且会给咱们启动一个服务css3

注:本小节的例子咱们采用单入口输入,示例以下web

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let htmlPlugins = ['index'].map(chunkName=>(new HtmlWebpackPlugin({
  filename:`${chunkName}.html`,
  chunks:[chunkName]
})));
module.exports = {
  devServer:{
    port:3000, //指定端口号
    open:true, // 是否自动打开浏览器
    compress:true, // 是否启用gzip压缩
    contentBase:'./dist' // 指定启动静态服务的文件目录
    // 经过webpack-dev-server打包的结果放到内存中,并且目录是当前的根目录
  },
  mode: 'development',
  entry: {
    index: './src/guYan.js',
  },
  output: {
    filename: '[name].js',
  },
  plugins: [
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: ['**/*']
    }),
    ...htmlPlugins,
  ]
}
复制代码
  • 经过npx webpack-dev-sever启动来查看结果

配置loader

  • 做用:webpack 只能理解 JavaScriptJSON 文件。loaderwebpack 可以去处理其余类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。
  • 特色
    • 执行顺序:从右向左,从下到上
    • 分类:前置(enforce:'pre')、普通(enforce:'normal')、后置(enforce:'post')
    • 参数类型:数组,字符串,对象

处理css

  • 全局建立一个style文件夹,并在其中建立一个index.css文件,并在src/guYan.js中引入
/*index.css*/
body{
    background:yellow;
}
复制代码
  • 安装css-loader,style-loader(npm install css-loader style-loader --save-dev)
    • 原理:经过css-loadercss文件处理成字符传形式,经过style-loaderhtml中建立<style>标签并将css-loader处理后的字符串插入其中
  • webpack.config.js中配置loader
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let htmlPlugins = ['index'].map(chunkName=>(new HtmlWebpackPlugin({
    template:'./public/index.html',
    filename:`${chunkName}.html`,
    chunks:[chunkName],
    minify:{
        removeAttributeQuotes:true,
        collapseWhitespace:true
    },
    hash:true
})))
module.exports = {
    mode:'development',
    devServer:{
      port:3000,
      open:true,
      compress:ture,
      contentBase:'./dist'
    },
    entry:{
        index:'./src/guYan.js'
    },
    output:{
        filename:'[name].js'
    },
    plugins:[
        new CleanWebpackPlugin(),
        ...htmlPlugins
    ],
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            }
        ]
    }
}
复制代码
  • 运行npx webpack-dev-server结果以下

CSS相关

配置css-modules

  • 在平常的开发中咱们一般会将一些公共的样式抽离到一个common.css文件中,而后在咱们js文件中按需引入;这样咱们就会遇到css模块化的问题(css-modules),咱们举例说明如何配置解决这个问题
  • 修改src/guYan.js,在style目录下建立一个common.css文件
// guYan.js
import { other } from './other';
import '../style/index.css';
import commonStyle from '../style/common.css';
let div = document.createElement('div');
div.className = commonStyle.guYan;
div.innerHTML = 'GuYan';
document.body.appendChild(div);
console.log(other);
复制代码
/*common.css*/
.guYan{
    color:red;
}
复制代码
  • 配置webpack.config.js
// webpack.config.js
...
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader',
                     {
                         loader:'css-loader',
                         options:{
                             modules:true
                         }
                     }
                ]
            }
        ]
    }
...
复制代码
  • 运行npx webapck-dev-server

特殊注意loader的顺序必定要特别注意,若是就想把style-loader写在后面须要在其options中增长enforce:'post'参数或者在css-loaderoptions中增长enforce:'pre'参数npm

配置css3增长浏览器内核前缀

  • 修改style/common.css以下
/*common.css*/
.guYan{
  color: red;
  background: green;
  transform: rotateY(180deg);
}
复制代码
  • 安装postcss-loader(npm install postcss-loader --save-dev)
  • postcss-loader只是一个干活的,它不知道干什么活,因此须要一个东西来告诉它,它须要作的是增长前缀,这个东西就是autoprefixer,因此咱们安装autoprefixer(npm install autoprefixer --save-dev)
  • 如今咱们干活的(postcss-loader)有了,指挥干活的(autoprefixer)也有了,可是呢这个干活的(postcss-loader)比较装X,它要求这个指挥干活的(autoprefixer)不能像其余loader那样你随随便便在options对象中指挥我,你必须专门在个人配置文件(postcss.config.js)中指挥我干活,因此咱们须要在根目录下建立一个postcss.config.js文件

  • 配置postcss.config.js文件
// postcss.config.js
module.exports = {
    plugins:[
        require('autoprefixer')
    ]
}
复制代码
  • 配置webpack.config.js
// webpack.config.js
...
module:{
    rules:[
        {
            test:/\.css$/,
            use:[
                'style-loader',
                {
                    loader:'css-loader',
                    options:{
                        modules:true
                    }
                },
                'postcss-loader'
            ]
        }
    ]
}
...
复制代码
  • 运行npx webpack-dev-server

配置css预处理器

  • 预处理器分类
    • lesssass(node-sass),stylus
  • 预处理器对应loader
    • less-loadersass-loaderstylus-loader
  • 引入预处理器文件的位置
    • js文件
      • 配置对应的loader(以less为例)
        // webpack.config.js
        ...
        module:{
            rules:[
                {
                    test:/\.less$/,
                    use:[
                        'style-loader',
                        {
                            loader:'css-loader',
                            options:{
                                modules:true
                            }
                        },
                        'postcss-loader',
                        'less-loader'
                    ]
                }
            ]
        }
        ...
        复制代码
    • css文件
      • 配置对应的loader(以less为例)
        // webpack.config.js
        ...
        module:{
            rules:[
                {
                    test:/\.css$/,
                    use:[
                        'style-loader',
                        {
                            loader:'css-loader',
                            options:{
                                modules:true
                            }
                        },
                        'postcss-loader',
                        'less-loader'
                    ]
                }
            ]
        }
        ...
        复制代码

配置抽离css样式

上文中提到的样式,不难发现都是嵌套在html文件中的head里的<style>标签中的,可是在平常的开发中咱们通常都是单独在xxx.css文件中写样式,而后经过<link>引入,因此咱们接下来抽离css样式吧json

  • 安装mini-css-extract-plugin(npm install mini-css-extract-plugin --save-dev)
  • 配置webpack.config.js,须要注意的是:
    • 1.这个插件作的工做是将css-loader处理后的字符串写到一个指定的文件中,想要使其以<link>标签的形式引入,须要配合其自带的loader使用,即下文的MiniCssExtractPlugin.loader
    • 2.官方建议生产模式下使用MiniCssExtractPlugin.loader,开发模式使用style-loader
    // webpack.config.js
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');// 引入插件
        ...
    module.exports = {
          ...
        plugins:[
          new CleanWebpackPlugin(),
          ...htmlPlugins,
          new MiniCssExtractPlugin({ // 注册插件
              filename:'index.css'//指定抽离的文件名
          })
          ...
        ],
        module:{
            rules:[
              {
                  test:/\.css$/,
                  use:[
                      // 'style-loader' 
                      MiniCssExtractPlugin.loader, // 配合插件自身loader使用
                      ...
                  ]
              }
            ]
        }
    }
    复制代码
  • 运行npx webpack-dev-server结果以下

配置压缩抽离的css样式文件

  • 上述代码执行npx webpack --mode production,查看打包后的文件,你会发现咱们抽离的css文件并无像jshtml文件同样被压缩,这在咱们上线的时候确定是不容许的,因此咱们须要压缩它
  • 安装optimize-css-assets-webpack-plugin(npm install optimize-css-assets-webpack-plugin --save-dev)
  • 配置webpack.config.js文件
    // webpack.config.js
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
    ...
    module.exports = {
        ...
        optimization:{ // 配置优化项
            minimizer:[ // 手动指定压缩项
            new OptimizeCssAssetsWebpackPlugin({})
            ]
        }
        mode:'production'
        ...
    }
    复制代码
  • 执行npx webpack查看结果,发现咱们提取的css文件已经实现压缩
  • 可是你再看js文件没有压缩,这是由于当咱们没有手动配置压缩项的时候webpack内部本身实现了配置其自带的terser-webpack-plugin插件进行压缩,而咱们配置后覆盖掉了它内部本身的配置,因此咱们须要手动将terser-webpack-plugin配置到minimizer
// webpack.config,js
const TerserJSPlugin  = require('terser-webpack-plugin'); //webpack的内部插件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
...
module.exports = {
  ...
  optimization:{ 
      minimizer:[
      new TerserJSPlugin({}),// 手动加上压缩js
      new OptimizeCssAssetsWebpackPlugin({})
      ]
  }
  mode:'production'
  ...
}
复制代码
  • 执行npx webpack查看结果

图片相关

配置图片引入

  • 在根目录下建立image文件夹并准备一张guYan.jpg图片放入其中
  • src/guYan.js中引入guYan.jpg
// guYan.js
import url from '../image/guYan.jpg';
...
let img = new Image();
img.src = url;
documnt.body.appendChild(img)
复制代码
  • 安装file-loader(npm install file-loader --save-dev)
    • 做用:
      • 1.拷贝一个文件放到打包后的文件中
      • 2.返回拷贝的路径
  • 配置webpack.config.js
//webpack.config.js
...
module.exports={
    ...
    module:{
        rules:[
            ...,
            {
                test:/\.(jpg|png|gif)$/,
                use:'file-loader'
            }
        ]
    }
}
复制代码
  • 执行npx webpack --mode production查看打包后的文件,会发现生成一个拷贝的图片

配置图片压缩

  • 在上一小节咱们实现了图片的引入,可是在咱们的开发过程当中有一些Icon之类的咱们更但愿它能够转化为base64的格式压缩,因此这就须要咱们配置另外一个能够处理图片的loader,url-loader
  • 安装url-loader(npm install url-loader --save-dev)
  • 配置webpack.config.js
// webpack.config.js
...
module.exports={
    ...
    module:{
        rules:[
            ...,
            {
                test:/\.(jpg|png|gif)$/,
                use:{
                    loader:'url-loader',
                    options:{
                        limit:100*1024 // 指定压缩文件的最大字节,超过最大限制会自动调用file-loader处理
                    }
                }
            }
        ]
    }
}
复制代码
  • 执行npx webpack --mode production,查看打包后的文件目录并无生成拷贝的文件(尝试修改limit参数的大下感觉一下变化)

特殊注意:字体图标(xxx.eot,xxx.svg,xxx.ttf,xxx.woff,xxx.woff2)只能用file-loader数组

若是你给的limit过大,也就是说会将大的图片也会转成base64的格式会致使打包的时候会有一个性能的警告提示你文件过大,这样的时候你能够给一个performance:false属性来使打包的时候忽略性能问题的提示,可是通常咱们上线确定考虑性能的问题的,也就是说咱们通常不会将limit的值设置过大

  • 上面咱们只举例了在js文件中引用图片的例子,其实在开发中咱们也有可能直接在html文件中引用图片,安装咱们以前的打包方式你会发现会出现找不到图片,由于路径变了,解决这个问题咱们须要配置一个html-withimg-loader
// webpack.config.js
...
    {
        test:/\.html$/,
        use:'html-withimg-loader'
    }
...
复制代码

配置输出的图片增长公共前缀好比须要加域名

  • url-loaderoptions增长publicPath属性便可
//webpack.config.js
...
    options:{
        limit:2*1024,
        publicPath:'https://juejin.im/user/5b685661e51d4517df153771'
    }
...
复制代码

同理css``js增长前缀一个套路

配置分类打包

  • 图片
    • options中增长outputPath属性
  • css
    • 在抽离插件的filename参数属性前面配置文件夹的名字
  • html
    • html-webpack-plugin插件的filename属性前面配置文件夹的名字
  • js
    • 在出口参数(output)里的filename属性前面配置文件夹的名字
  • 执行npx webpack --mode production查看打包后的文件变化吧

JS相关

配置JS高级语法降级(经过babel一系列包)

  • 修改guYan.js文件以下
// guYan.js
class Animal{
    constructor(type){
        this.type = type;
    }
    getType(){
        return this.type
    }
}
let animal = new Animal('哺乳类');
console.log(animal.type);
复制代码
  • 安装babel-loader,@babel/core,@babel/preset-env(npm install babel-loader @babel/core @babel/preset-env --save-dev)
  • 配置webpack.config.js
// webpack.config.js
...
module.exports={
    ...,
    module:{
        rules:[
            ...,
            {
                test:/\.js$/,
                use:{
                    loader:'babel-loader',
                    options:{
                        presets:['@babel/preset-env'],// 起指挥loader怎么干活的做用
                    }
                },
                exclude:/node_module/, // 忽略掉不想用loader处理的文件
                include:path.resolve(__dirname,'./src') // 指定须要loader处理的文件
            }
        ]
    }
}
复制代码
  • 执行npx webpack --mode development,查看打包后的js文件,咱们发现,他内部实现了一个_classCallCheck,来做为转化咱们的class类。
// 删除后冗余的代码后的打包文件
(function(modules) {
	var installedModules = {};
	function __webpack_require__(moduleId) {
		if(installedModules[moduleId]) {
			return installedModules[moduleId].exports;
		}
		var module = installedModules[moduleId] = {
			i: moduleId,
			l: false,
			exports: {}
		};
		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
		module.l = true;
		return module.exports;
	}
	return __webpack_require__(__webpack_require__.s = "./src/guYan.js");
})
({
 "./src/guYan.js":
 (function(module, exports) {
eval(`function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var Animal =function () { function Animal(type) { _classCallCheck(this, Animal); this.type = type; } _createClass(Animal, [{ key: \"getType\", value: function getType() { return this.type; } }]); return Animal; }(); var animal = new Animal('哺乳类'); console.log(animal.type);`);
 })
});
复制代码
  • 新建一个src/otherEs6.js文件,在其中再用class定义一个类导出,在src/guYan.js中引入这个文件,再执行编译。你会发现他内部实现这个公共的_classCallCheck代码,实现了两次,因此咱们须要提取这个公共的代码
  • 安装@babel/runtime,@babel/plugin-transform-runtime(npm install @babel/runtime @bebel/plugin-transform-runtime --save-dev)
  • 配置webpack.config.js文件
// webapack.config.js
...
    test:/\.js$/,
    use:{
        loader:'babel-loader',
        options:{
            presets:['@babel/preset-env'],
            plugins:['@babel/plugin-transform-runtime']
        }
    }
...
复制代码
  • 执行npx webpack --mode development,查看打包后的js文件,比较两次有什么不一样

配置JS的一些API降级处理,如promise(为了兼容IE)

  • 方案一,经过@babel/preset-env+core-js@3
    • 安装core-js@3(npm install core-js@3 --save)
    • 配置webpack.config.js
    // webpack.config.js
    ...
    test:/\.js$/,
    use:{
        loader:'babel-loader',
        options:{
            preset:[
                [
                    '@babel/preset-env',
                    {
                        useBuiltIns:'usage',// 只转化使用的API
                        corejs:{version:3}
                    }
                ]
            ]
        }
    }
    ...
    复制代码
  • 方案二在入口文件中引入@babel/polyfill
  • 方案三,经过@babel/plugin-transform-runtime+@babel/runtime-corejs3
    • 安装@babel/runtime-corejs3(npm install @babel/runtime-corejs3)
    • 配置webpack.config.js
    // webapck.config.js
    ...
        test:/\.js$/,
        use:{
            loader:'babel-loader',
            options:{
                presets:['@babel/preset-env'],
                plugins:[
                    [
                        '@babel/plugin-transform-runtime',
                        {
                            "absoluteRuntime": false,
                            "corejs": {version:3},
                            "helpers": true,
                            "regenerator": true,
                            "useESModules": false
                        }
                    ]
                ]
            }
        }
    ...
    复制代码

像装饰器和类的属性这些更高级的须要再去配插件去处理,这里我就不一一举例了(@babel/plugin-proposal-decorators@babel/plugin-proposal-class-properties)

ESlint相关

  • 安装 eslint,eslint-loader(npm install eslint eslint-loader --save-dev)
  • 配置webpack.config.js
// webpack.config.js
...
    test:/\.js$/,
    use:'eslint-loader',
    enforce:'pre' // 强制在编译以前执行 
...
复制代码
  • 配置eslint
    • 方案一,在eslint中去选择自动生成而后引入项目列表
    • 方案二,本身手动配置
      • 运行npx eslint --init
  • 配置webpack.config.js
// we
复制代码

配置TS

  • ts-loader
  • tsconfig.json

配置代理

优化策略

常见pluginloader的原理及实现

基于create-react-app实现一个简单的脚手架

注: 参考文档

相关文章
相关标签/搜索