Webpack配置文件

/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const webpack = require('webpack');
//以下都是插件的引入
const HappyPack = require('happypack');
//html-webpack-plugin插件, 让webpack打包后生成html文件并自动引入打包后的js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CompressionPlugin = require('compression-webpack-plugin');


/*;
webpack本身是, node的一个第三方模块包, 用于打包代码;
把很多文件打包整合到一起, 缩小项目体积, 提高加载速度
功能:
less/sass -> css
ES6/7/8 -> ES5 处理js兼容
支持js模块化
处理css兼容性
html/css/js -> 压缩合并
所有要被打包的资源都要跟入口产生直接/间接的引用关系
*/
/*
module:每个import引入的文件就是一个模块(也就是直接手写的代码)
chunk:当module源文件传到webpack进行打包时,webpack会根据文件引用关系生成chunk(也就是module在webpack处理时是chunk)
bundle:是对chunk进行压缩等处理后的产出(也就是打包后可以直接运行的文件)*/
//webpack只能解析js和json这样的文件,loader可以让webpack解析其它类型的文件
//并将这些文件转化为有效的模块
//babel-loader 可以让webpack 对高版本js语法做降级处理后打包
const babelLoader = [
  {
    loader: 'babel-loader',
    options: {
/*
sourceType可以是 “script” | “module” | “unambiguous”,默认其实是"module"
"script": 使用正常的script标签里的js语法解析文件,没有import/export,并且不是严格模式
"module": 使用ES6 module解析文件,自动为严格模式,支持import/export语法
"unambiguous": babel根据文件中是否出现import/exports来确定是否处于"module"模式还是"script"模式
*/
      sourceType: 'unambiguous',
      babelrc: false,
// 预设:转码规则
//Presets就是一组转换JavaScript插件的集合。执行顺序从右到左,和loader一样
      presets: ['babel-preset-expo'],
//Babel可以使用各种插件针对不同特性JavaScript特性进行转换。
      plugins: [
        ['import', { libraryName: 'antd-mobile', style: true }],
        [
          'module-resolver',
          {
            alias: {
              'react-native-reanimated': path.resolve(
                __dirname,
                'node_modules/react-native-reanimated/src/Animated.js'
              ),
            },
          },
        ],
      ],
    },
  },
];

// 获取文件绝对路径
function resolve(...pathNames) {
  const paths = [__dirname, ...pathNames];
  return path.resolve(...paths);
}


//为了获取环境变量,需要将其写成函数形式
//如果你想根据webpack.config.js中的mode变量改变行为,你必须导出一个函数而不是对象
module.exports = (env, argv) => {
  const IS_PROD = argv.mode === 'production';
  const CDN_PATH = '/';
  const PUBLIC_PATH = IS_PROD ? CDN_PATH : '/';
  const webpackConfig = {


    modules: false, // 默认true,是否添加构建模块信息
//主要包含了webpack在编译源代码时的一些模块统计信息。这些统计数据可以用来分析应用程序的依赖关系图,也可以用来优化编译速度。
// 默认true,是否添加children信息(设置为false,解决webpack4打包时出现:Entrypoint undefined = index.html)
    stats: { children: false },

/*
mode 表示webpack当前的环境以及对不同的环境的配置。
一共有production、development和none三种。
development 开发阶段,简易打包,打包速度快
production 发布阶段,打包精细,打包速度慢
*/
    mode: 'production',


//入口
// 默认为 ./src
// 这里应用程序开始执行
// webpack 开始打包
//对象中的每一对属性对,都代表着一个入口文件,因此多页面配置时,肯定是要用这种形式的entry配置。
//value如果是字符串,而且必须是合理的noderequire函数参数字符串。比如文件路径:'./app.js'(require('./app.js'));比如安装的npm模块:'lodash'(require('lodash'))
    entry: {

//指定了把那些模块打包为vendor
//value如果是数组,则数组中的元素需为上面描述的合理字符串值。数组中的文件一般是没有相互依赖关系,但又出于某些原因需要打包在一起。
      vendor: [
        'react',
        'core-js',
        'dva-loading',
        'fastclick',
        'react-native-web',
        'react-dom',
        'rc-form',
        'react-navigation',
        'react-singleton',
        'react-imageview',
      ],
      app: './index.js',
    },

//webpack通过resolve实现模块的依赖和引用
    resolve: {
//通过别名来把原来导入路径映射成一个新的导入路径
      alias: {

        'react-native': 'react-native-web',
        'react-native-reanimated': path.join(__dirname, 'node_modules/react-native-reanimated/src/Animated.js'),
        ),
        'react-native-gesture-handler': path.join(__dirname, 'node_modules/react-native-gesture-handler'),
      },
//esolve.modules配置webpack去哪些目录下寻找第三方模块。默认是去node_modules目录下寻找。有时你的项目中会有一些模块大量被其他模块依赖和导入,由于其他模块的位置分布不定,针对不同的文件都要去计算被导入模块文件的相对路径,这个路径有时候会很长,例如:import './../../components/button',这时你可以利用modules配置项优化,假如那些大量导入的模块都在./src/components目录下:
      modules: [resolve('src/components'), resolve('src'),  'node_modules', './node_modules'],

//使用的扩展名,相同文件名顺序优先识别
      extensions: ['.web.ts', '.ts', '.web.tsx', '.tsx', '.web.js', '.js', '.less', '.web.jsx', '.jsx', '.json'],
    },

// webpack 如何输出结果的相关选项
    output: {
// 所有输出文件的目标路径
// 必须是绝对路径(使用 Node.js 的 path 模块)
      path: path.resolve(__dirname, 'public'),
// 用于输出文件的文件名
//[]是webpack自带的默认生成文件名的方法
      filename: IS_PROD ? 'assets/scripts/[name].[chunkhash].js' : 'assets/scripts/[name].js',
// 用于动态加载的chunk
      chunkFilename: IS_PROD ? 'assets/scripts/[chunkhash].chunk.js' : 'assets/scripts/[id].chunk.js',
//配置公共路径
// 输出解析文件的目录,url 相对于 HTML 页面
      publicPath: PUBLIC_PATH,
    },


/*
1.为静态文件提供web服务
2.自动刷新和热替换(HMR)
自动刷新指当修改代码时webpack会进行自动编译,更新网页内容
HMR:Hot Module Replacement 热模块替换。当修改代码时, webpack 默认会将所有模块全部重新打包编译,整个页面重新加载,速度很慢。HMR 热模块替换支持在程序运行中(webpack-dev-server 已启动),修改哪个模块,就自动修改(替换、添加、删除)该模块。
简而言之:起一个开发服务器, 在电脑内存中打包, 缓存一些已经打包过的内容, 只重新打包修改的文件, 最终运行加载在内存中给浏览器使用
*/
    devServer: {
// 运行代码的目录
      contentBase: path.resolve(__dirname, 'public'),
//代表的是启动的时候,就在的页面
      index: 'index.html',
//指定监听请求的端口号。
      port: 8082,
//historyApiFallback,它主要的作用是解决SPA页面在路由(前端路由)跳转之后,进行页面刷新时,返回404的错误。
//可以配置from来匹配路径,决定要跳转到哪一个页面;
      historyApiFallback: {
        rewrites: [{ from: /^.*$/, to: 'index.html' }],
      },
    },
    node: {
      global: true,
    },


    module: {
//通过配置多个对象加载不同文件
// 模块规则(配置 loader、解析器等选项)
      rules: [
        {
//test属性使用正则表达式定义加载文件类型
          test: /\.(svg)$/,
//use属性 在定义转化的时候应该使用哪个loader来进行转化;如果有多个,会逆向转化。
// use数组里从右向左运行
// 先用 css-loader 让webpack能够识别 css 文件的内容并打包
// 再用 style-loader 将样式, 把css插入到dom中
/万物皆模块, 引到入口, 才会被webpack打包, css打包进js中, 然后被嵌入在style标签插入dom上
          use: ['svg-sprite-loader'],
//exclude和include更多的像是在test匹配的基础上做详细的配置,或者说成是test的子集。
//include 指定要包含的文件
          include: [require.resolve('antd-mobile').replace(/warn\.js$/, '')],
        },
        {
          test: /\.jsx?$/,
          include: [
            path.resolve(__dirname, 'index.web.js'),
            path.resolve(__dirname, 'envs'),
            path.resolve(__dirname, 'src'),
            path.resolve(__dirname, './themes'),
            path.resolve(__dirname, 'node_modules/react-native-screens'),
            path.resolve(__dirname, 'node_modules/react-native-reanimated'),
            path.resolve(__dirname, 'node_modules/@react-navigation'),
            path.resolve(__dirname, 'node_modules/react-navigation'),
            path.resolve(__dirname, 'node_modules/react-native-screens'),
            path.resolve(__dirname, 'node_modules/react-native-gesture-handler'),
            path.resolve(__dirname, 'node_modules/react-native-tab-view'),
            path.resolve(__dirname, 'node_modules/react-native-storage'),
            path.resolve(__dirname, 'node_modules/react-native-safe-area-view'),
            path.resolve(__dirname, 'node_modules/react-navigation-deprecated-tab-navigator'),
            path.resolve(__dirname, 'node_modules/react-navigation-tabs'),
            path.resolve(__dirname, 'node_modules/react-navigation-drawer'),
            path.resolve(__dirname, 'node_modules/react-navigation-stack'),
            path.resolve(__dirname, 'node_modules/react-navigation-redux-helpers'),
          ],
          loader: 'happypack/loader?id=babel',
        },
        {
          test: /\.tsx?$/,
          include: [
            path.resolve(__dirname, 'index.web.js'),
            path.resolve(__dirname, 'envs'),
            path.resolve(__dirname, 'src'),
            path.resolve(__dirname, './themes'),
            path.resolve(__dirname, 'node_modules/react-native-screens'),
            path.resolve(__dirname, 'node_modules/react-native-reanimated'),
            path.resolve(__dirname, 'node_modules/@react-navigation'),
            path.resolve(__dirname, 'node_modules/react-navigation'),
            path.resolve(__dirname, 'node_modules/react-native-screens'),
            path.resolve(__dirname, 'node_modules/react-native-gesture-handler'),
            path.resolve(__dirname, 'node_modules/react-native-tab-view'),
            path.resolve(__dirname, 'node_modules/react-native-storage'),
            path.resolve(__dirname, 'node_modules/react-native-safe-area-view'),
            path.resolve(__dirname, 'node_modules/react-navigation-deprecated-tab-navigator'),
            path.resolve(__dirname, 'node_modules/react-navigation-tabs'),
            path.resolve(__dirname, 'node_modules/react-navigation-drawer'),
            path.resolve(__dirname, 'node_modules/react-navigation-stack'),
            path.resolve(__dirname, 'node_modules/react-navigation-redux-helpers'),
          ],
          use: [
            'happypack/loader?id=babel',
            {
              loader: 'ts-loader',
              options: {
                transpileOnly: true,
                allowTsInNodeModules: true,
              },
            },
          ],
        },
//图片处理
        {
          test: /\.(gif|jpe?g|png)$/,
// 匹配文件, 尝试转base64字符串打包到js中
          loader: 'url-loader',
          options: {
// 配置limit, 超过512k, 不转
            limit: 512,
// 配置输出的文件名,[hash:16]: hash值取16位,[ext]: 使用之前的文件扩展名
            name: 'assets/files/[name].[hash:16].[ext]',
          },
        },
      ],
    },


    plugins: [

//HappyPack是一个通过多线程来提升webpack打包速度的工具。
//需要为每个loader配置一个id,否则 HappyPack 无法知道rules与plugins如何一一对应。
      new HappyPack({
        id: 'babel',
        loaders: babelLoader,
//指示对应 loader 编译源文件时同时使用的进程数,默认是 3
        threads: 4,
      }),


// DefinePlugin 最为常用的用途就是用来处理我们开发环境和生产环境的不同。
//比如一些 debug 的功能在生产环境中需要关闭、开发环境中和生产环境中 api 地址的不同。
      new webpack.DefinePlugin({
//通过配置了DefinePlugin,那么这里面的标识就相当于全局变量,你的业务代码可以直接使用配置的标识。
        __DEV__: false,
      }),


//在使用时将不再需要import和require进行引入,直接使用即可。
      new webpack.ProvidePlugin({
        ENV: `envs/${argv.mode || 'development'}`,
      }),


//忽略第三方包指定目录,让这些指定目录不要被打包进去
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),

//自定义打包的html模版,和输出文件名字
      new HtmlWebpackPlugin({
        filename: 'index.hbs',
        template: './src/views/index.ejs',
      }),

/*它的作用是将 CSS 代码从 JavaScript 中分离出来,生成单独的 CSS 文件。
使用 mini-css-extract-plugin 可以避免将 CSS 代码打包到 JavaScript 文件中,减少 JavaScript 的体积,同时也可以使得 CSS 文件可以被浏览器缓存,提高页面加载速度。*/

      new MiniCssExtractPlugin({
//filename 是生成的 CSS 文件名,[name] 会被替换为入口文件名,[contenthash] 会根据文件内容生成//一个 hash 值,用于版本管理。
        filename: `assets/styles/[name]${IS_PROD ? '[contenthash]' : ''}.css`,
        allChunks: true,
      }),
    ],

//公共部分提取: optimization
//多入口文件的项目,难免在不同的入口存在相同的部分(使用了相同组建、公共样式等),将多个css chunk合并成一个css文件
    optimization: {
//根据这个来拆分chunk
      splitChunks: {
// 要提取的chunk最少被引用1次
        minChunks: 1,
// 分割chunk的组
//根据cacheGroups的配置进来分包并包的
        cacheGroups: {
 // node_modules文件会被打包到vendors组的chunk中。--> vendors~xxx.js
// 满足上面的公共规则,如:至少被引用一次
          vendors: {

/*
async:当设置chunks的值为async时,只有在异步加载模块的时候,才会进行分包处理该模块
initial:同步加载模块的时候,也会进行分包处理。
all:同步异步都会进行分包处理
*/
            chunks: 'initial'
//提取出来的文件名
            name: 'vendor',

            test: 'vendor',
// 如果发现页面中未引用公共文件,加上enforce: true
            enforce: true,
          },
        },
      },
    },
  };


//判断不同模式添加不同插件。
  if (argv.mode === 'production') {
    // // gizp 压缩

/*gzip 可以压缩所有的文件,但是我们不需要对所有文件进行压缩,一般情况对我们写的代码(css,js,html)之类的文件有很好的压缩效果,图片之类文件不会被 gzip 压缩太多,因为它们已经内置了一些压缩,再去压缩可能会让生成的文件体积更大一些。*/
    webpackConfig.plugins.push(
      new CompressionPlugin({
        test: /\.js|\.css/,
        algorithm: 'gzip',
        threshold: 10240, // 10K以内不进行压缩
        minRatio: 0.8,
      })
    );
  }

  if (argv.mode === 'development') {
//devtool的值有20+种。它有固定的模式。
//通过关键词的组合,就可以生成用于各种场景的Source Map
//指定devtool时,要与mode配合使用。
//Source Map,有了它浏览器就可以从转换后的代码直接定位到转换前的代码,精准定位错误代码。
//选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。
//所以我们要根据开发环境,或者生产环境的不同需求配置不同的格式选项
//在webpack中,可以通过devtool选项来配置Source Map。
    // map文件生成
    webpackConfig.devtool = 'source-map';
    // eslint-disable-next-line function-paren-newline
    webpackConfig.plugins.push(
      new HtmlWebpackPlugin({
        filename: 'index.html',
        template: './src/views/index.ejs',
      })
    );
  }

  return webpackConfig;
};




/*
webpack-cli 命令的选项比较多,详细可以通过 webpack-cli 的文档进行查阅,这里总结我们日常用的最多的几个选项(options):

–config:指定一个 Webpack 配置文件的路径;
–mode:指定打包环境的mode,取值为development和production,分别对应着开发环境和生产环境;
–json:输mode出 Webpack 打包的结果,可以使用webpack --json > stats.json方式将打包结果输出到指定的文件;
–progress:显示 Webpack 打包进度;
–watch, -w:watch 模式打包,监控文件变化之后重新开始打包;
–color, --colors/–no-color, --no-colors:控制台输出的内容是否开启颜色;
–hot:开启 Hot Module Replacement模式,后面会详细介绍;
–profile:会详细的输出每个环节的用时(时间),方便排查打包速度瓶颈。
$ webpack -p//压缩混淆脚本,这个非常非常重要!
$ webpack -d//生成map映射文件,告知哪些模块被最终打包到哪里了其中的 

如果出于某些原因,需要根据特定情况使用不同的配置文件,则可以通过在命令行中使用 --config 标志修改

"scripts": {
  "build": "webpack --config prod.config.js"
}
*/

vendorchunk是由webpack打包出来的文件,chunk是指webpack在进行模块的依赖分析的时候,代码分割出来的代码块。module是开发中的单个模块。在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值