webpack5

244 阅读16分钟

问题与答案

一. 简述前端兼容性的解决方案及不同工具的使用(CSS及JS)

1. 针对css

  1. 不同的浏览器中都有默认的一些css 样式,比如margin,padding 等,各浏览器不同。
    • 解决方法: 使用css reset 来重置浏览器的默认样式
  2. 针对不同浏览器,某些css 属性需要加前缀,比如 -moz-transform
    • 解决方法: 使用 postcss-loader。postcss-loader 这个类似个工具包,需要往里面添加插件配置,也就是配置插件 options: {postcssOptions: {plugins: [require('autoprefixcer')]}} ,或者预设插件{plugins: [require('postcss-preset-env')]}}
    • postcss-loader 会根据 (1) 项目下面的package.json 中的 browserlist 选项 (2) .browserslistrc 文件 里面定义的内容 (3) webpack 默认安装的兼容平台 三种方式做兼容操作

2. 针对js

  1. 不同浏览器的一些兼容写法,比如监听或者获取大小等监听,可以使用jquery 解决
  2. 对于遇到es6 以及更新的语法,比如箭头函数,作用域,promise, generator, symbole 时,就需要使用babel-loader
    • babel-loader 和 postcss-loader 一样,本质上是一个工具包,需要往里面添加工具, 比如preset-env 可以转换箭头函数,作用域等
    • @babel/polifill(webpack5 前, 很大), 可以让promise, generator, symbole 直接作用于各浏览器
    • webpack5 后, 替代 @babel/polifill ,使用 core-js regenerator-runtime(要注意useBuiltIns的用法,具体方式可以看babel)

二. 列举三种常见的webpack打包优化手段及使用步骤

1. 第三方扩展设置CDN

  1. 如果自己有cdn服务器
    • 将静态文件放置在服务器上
    • 设置publicPath 告诉html 服务器所在地址,在打包后html引用的脚本路径就会加上服务器前缀
  2. 如果自己没有cdn服务器
    • externals: {lodash: '_'}, 将第三方包排除,不进行打包
    • 在html 中引入第三方包 的cdn 地址

2. 打包/使用 dll 库

对不常变动的,体积较大的库使用DllPlugin 动态链接库进行打包

  1. 设置入口为想要打包的库, 使用 webpack.DllPlugin 进行打包出js 和 manifest.json 文件
  2. 在需要打包的项目中, 使用webpack.DllReferencePlugin ,把dllplugin 打包出来的manifest 和 js 关联起来
  3. 在需要打包的项目中,使用 externals 将第三方包移除,不进行打包
  4. 在模板html 文件中引入 dll库对应的js 文件, 使用CopyWebpackPlugin 插件将打包后的dll 相关文件移动到打包输出的文件中

3. css 抽离和压缩

  • 抽离: mini-css-extract-plugin(针对webpack5)
  • 压缩: css-minimizer-webpack-plugin(当时使用这个插件时,需要同时开启minimize: true才生效, 并且开启时报了一个postcss plugin 的错误,原来是配置文件中用了postcss-loader, 却没有安装postcss 导致的问题 )

4. css treeshaking

  • purgecss-webpack-plugin

5. terserplugin 压缩js

  • webpack 5 自带,webpack4 需要引入
  • 需要开启minimize: true, 如果是false代表不开压缩功能

6. usedExports

  • 标记未使用(后使用terser-webpack-plugin 可以把标记的内容删除,配合minimize:true)

7. sideEffects

  • 如果引用了一个文件,import 'x.js' 而没有导出里面的 任何模块 ,比如import {add} from 'x.js',并且在package.json 中蛇者 sideEffects:false, 那么就不会执行到到x.js 整个文件,就算里面有 window.x = 123, 也不会执行。
  • 如果希望某些没有被引用模块的文件也能被执行的话,可以设置 sideEffects:true或者sideEffects:['x.js']

8. 资源压缩

  • compression-webpack-plugin

9. inlineChunkHtmlPlugin的使用

  • inline-chunk-html-plugin
  • 把外链src 的内容以,注入到html 中,与html-webpack-plugin 结合使用

常用的网站

  1. caniuse.com/
  2. https://autoprefixer.github.io/
  3. https://www.babeljs.cn/docs/babel-preset-env

webpack 打包概述

一. 怎么让webpack工作

  1. 全局安装webpack 和 webpack-cli 后, 在命令行中执行webpack 命令,(webpack 会默认将src/index.js 作为入口文件)(缺点:全局安装,每个人安装的版本不一样)
  2. 局部安装webpack 和 webpack-cli 后, 在命令行中执行 npx webpack 命令,(npx 会找到node_module 下面 .bin 目录下面的 webpack 文件执行)(缺点:在需要修改一些参数的时候,每次启动的命令行太长, 比如每次需要输入 npx webpack --entry ./src/main.js)
  3. 局部安装webpack 和 webpack-cli 后, 在package.json 中, 的scripts 中,添加 "build": "webpack --entry ./src/main.js", 直接在命令行中执行命令 npm run build (缺点:无法做过于复杂的配置)
  4. 局部安装webpack 和 webpack-cli 后,添加一个webpack.config,js, 并且在里面做一些入出口,插件等配置等。 在package.json 中, 的scripts 中,添加 "build": "webpack", 直接在命令行中执行命令 npm run build (webpack 会自动根据配置文件webpack.config.js 的内容执行)
  • 如果需要修改webpack.config.js 的文件的名字为diy.config.js,可以在package.json 中的命令, 将"build": "webpack --config diy.config.js"

二. 如何调试webpack的打包流程

  1. 创建一个run.js 文件
  2. run.js 文件中写如下代码 const webpack = require('webpack');const conf = require('./webpack.config.js'); const compiler = webpack(conf);compiler.run(function(err,stats){ console.log('错误:::', err) console.log('结果:::', stats.toJson())})
  3. 执行 node run.js 命令,在vscode 调试界面中进行调试,后续,将require('webpack')中的webpack 改成自己手写的库可进行验证

三. 初始化一个 js 项目需要配置什么

  1. 需要的最基础的依赖
    • babel, babel-loader, @babel/core @babel/preset-env
    • html-webpack-plugin
    • webpack, webpack-dev-server, webpack-merge, webpack-cli
  2. 兼容需要的依赖与配置(polifill 兼容性补充 @babel/preset-env)
    • @babel/polyfill ( webpack 4, webpack 5之后不需要)
    • core-js/stable (ECMAScript 的核心功能)
    • regenerator-runtime/runtime (转换gennerator function 的工具包,比如promise 以及 async await 底层都是用的 generator)
    • 配置上 { useBuiltIns: 'usage', corejs: 3 }
  3. 模块热替换功能需要的依赖与配置
    • devServer 设置 hot: true
    • 在入口文件添加哪些模块开启热更新的配置 if(module.hot){module.hot.accept(['./title'], ()=>{console.log('更新完后的操作')})}
    • 如果不生效可能是项目项目的.browserslistrc 冲突了,所以可以在webpack 中设置target: 'web',在开发阶段屏蔽掉 browserslistrc

四. 初始化一个react 项目需要配置什么

  1. 需要的最基础的依赖
    • react, react-dom
    • babel, babel-loader, @babel/core @babel/preset-env @babel/preset-react
    • 需要 初始化一个 js 项目 最基础的依赖
  2. 兼容需要的依赖与配置(polifill 兼容性补充 兼容性补充 @babel/preset-env)
    • 方式和初始化一个 js 项目的方式相同
  3. 模块热替换功能需要的依赖与配置
    1. 对于模块文件
      • webpack.config.js 中需要使用插件@pmmmwh/react-refresh-webpack-plugin
      • babel.config.js 中需要使用插件 react-refresh/babel
    2. 对于工具文件
      • 工具文件热更新的方式 和 初始化一个 js 项目 的方式相同
      • 模块文件不能像被module.hot 引入,否则就会造成模块文件state改变,但是视图更新不了

五. 初始化一个vue 项目需要配置什么

  1. 需要的最基础的依赖 -vue, vue-template-compiler, vue-loader
  2. 兼容需要的依赖与配置(polifill 兼容性补充 兼容性补充 @babel/preset-env)
    • 方式和初始化一个 js 项目的方式相同
  3. 模块热替换功能需要的依赖与配置
    • 对于 vue2 来说 vue-loader@14 自动带有日替换功能
    • 对于 vue2 来说 vue-loader@15 需要自己引入 vue-loader/lib/plugin, 通过new VueLoaderLibPlugin 引入,否则会报错
    • 对于 vue3 来说 需要使用 vue-loader@16

六. loader

1. 为什么需要loader

在没有使用loader 之前, webpack本身 不能直接处理js 模块以外的其他类型的文件, 需要先使用loader 去对其他类型的文件进行处理

2. loader 是什么

loader 也是一个模块, 里面导出一个函数,接收一定参数

3. loader 的使用

  • webpack4 :
  1. 行内的loader
    • 固定语法:loader + 英文! , 多个loader 用!分隔,就行,如下 import 'css-loader! ./login.css '
  2. 配置文件的loader, 三种方式
    • rules: [{test:/\.css$/, use:[{loader: 'css-loader'}]}]
    • rules: [{test:/\.css$/, use: ['css-loader']}]
    • rules: [{test:/\.css$/, loader: 'css-loader'}]

4. 多个loader 的处理顺序

loader 默认处理顺序是 从右往左, 从下往上,比如['style.loader', 'css-loader'], webpack 会使用 css-loader 处理后将结果传入 style-loader 进行处理, 再传入compire

5.常用的loader

  1. css-loader

    • 将css语法转换为js 语法
  2. style-loader

    • 将转换后的css 挂载到html 中去
  3. less-loader

    • less: 先安装less, 可以直接在命令行中使用 npx less ./src/index.less index.css, less 就可以直接将less 转换为css 文件
    • less-loader: 不通过命令行的方式,而让webpack 自动将less 转换为css。less-loader 里面使用到了less 来将less 转换为css, 所以我们在安装less-loader 的同时,也需要安装less
  4. postcss-loader

    • postcss: 先安装 postcss , 他是通过javascript 转换样式的工具, 是个独立工具,解析器, 本身什么也不能做, 如果想要对css 做某些操作,比如加前缀,需要引用插件
    • postcss-cli: 在安装完postcss 后,再安装postcss-cli就可以在命令行中使用 npx postcss -o ret.css ./src/index.css, 在不安装任何插件之前, 什么都没改变
    • autoprefixer: 安装了插件后,npx postcss --use autoprefixer -o ret.css ./src/index.css ,执行完后,可以在ret.css 中看到加了前缀的样式
    • postcss-loader: 不通过命令行的方式,而让webpack 自动 对 css 执行操作。postcss-loader 里面使用到了 postcss , 但这个工具什么也做不了, 如果想要做一些事情,需要使用插件 options: {postcssOptions: {plugins: [require('autoprefixcer')]}}
    • postcss-preset-env: 预设, 不同插件的集合(包括了autoprefixcer),options: {postcssOptions: {plugins: [require('postcss-preset-env')]}} 或者 options: {postcssOptions: {plugins: ['postcss-preset-env']}}
    • postcss.config.js: postcss 可能在 css 文件和less 文件都要引用, 为了不要冗余代码, 需要用一个文件做配置 module.export={plugins: ['postcss-preset-env']}
  5. file-loader

    • img src,可以使用import x from 'x' , 或者 require('图片资源')
      • 当使用requier('图片资源')方式导入图片时,有两个注意事项
        1. webpack4 引用文件的时候 require('x') 就可以拿到文件
        2. webpack5 需要使用require('x').default, 或者在 file-loader 中使用 options: {esModule: false}
    • img background , 使用url(图片资源)
      • 在被 css-loader 进行转换时,会将他转换为 require(), 这个时候会发现图片加载不出来,
      • 因为require 会将他转为 es module , 所以我们需要在配置 css-loader 时,需要设置参数options: {esModule: false}, 告诉他不要返回 es module , 直接返回资源
  6. url loader

    • url-loader 的作用是把图片转换成base64, 内嵌在文件中,可以减少请求次数,但是增加了请求体积,有可能增加首屏请求时间
    • file-loader 的作用是将资源拷贝到指定目录,分开请求
    • url-loader 的内部也可以 调用file-loader
    • 最佳实践: 使用limit: 2 * 1024 (2kb), 当小于指定大小时,才转成base64, 大于指定大小,则在url-loader内部调用file-loader
  7. webpack 5 中的asset

    • 常用的配置

    image.png

    • 具体的使用:

    image.png

  8. babel-loader

  • babel-loader: 不通过命令行的方式,而让webpack 自动 对 css 执行操作。babel-loader 里面使用到了 babel , 但这个工具什么也做不了, 如果想要做一些事情,需要使用插件 options: {plugins: ['@babel/plugin-transform-arrow-function', '@babel/plugin-transform-block-scoping']} 或者 options: {presets: ['@babel/preset-env']}
  • 指定兼容哪些浏览器, 可以通过browserslistrc, 也可以options: {presets: ['@babel/preset-env', {targets: chrome 91}]}
  • babel.config.js(cjs,mjs,json)(babel 7 之后,使用多包管理方式)/ .babelrc.json(babel7 之前, 使用多仓库管理方式)

6. loader 使用中的一些注意点

  1. css-loader 将当前的css 语法转换为当前js可以使用的模块的类型,但并不能把样式放到界面使用, 如果想要在界面上看到样式变化,还需要使用style-loader
  2. 当多个loader 顺序使用时,比如css-loader, postcss-loader,首先使用过的loader, 这里时 postcss-loader 不会回头去在 css-loader 处理完成之后再处理一次。 这样就会产生一个问题, 比如 css-loader遇到import时,会把引入的文件原样输出,如果引入的文件中带有一些需要兼容的样式,postcss-loader就无法对他进行处理了。
    • importLoaders 配置项 在使用css-loader 时使用,可以在css-loader处理完后再返回去给postcss-loader 处理, 使用方式如下:后面的数字表示返回几层loader处理
    • rules: [{test:/\.css$/, use:[{loader: 'css-loader', options: {importLoaders: 1}]}]

七. Plugin

1. 为什么需要plugin

  • loader: 转换 特定类型文件
  • plugin: 操作js模块,可以做更多的事情, 贯穿webpack打包过程的全部生命周期

2. plugin是什么

plugin 本质上是个类, 使用时需要实例化

3. plugin 的使用

  • const { CleanPlugin } = require('webpack') plugins: [new CleanPlugin()]

4. 多个plugin的执行顺序

plugin 中用了许多钩子函数(webpack/tapable), 事件都是在钩子中触发的,所以配置时不需要关心plugin 的顺序

5. 常用的plugin

  1. html-webpack-plugin

  2. webpack.DefinePlugin

  3. bable 相关

    • 为什么需要babel? JSX, TS, ES6+ --> 浏览器平台直接使用
    • 安装: npm install @babel/core @babel/cli (@babel/core, 微内核, 起到转换的作用,转换过程如果想要做修改,要安装相应的插件包, @babel/cli 可帮助我们在命令行中是使用) npx babel src --out-dir build
    • @babel/plugin-transform-arrow-function: npx babel src --out-dir build --plugins=@babel/plugin-transform-arrow-function
    • @babel/plugin-transform-block-scoping: npx babel src --out-dir build --plugins=@babel/plugin-transform-arrow-function,@babel/plugin-transform-block-scoping
    • @babel/preset-env: 预设, 插件的集合 npx babel src --out-dir build --presets=@babel/preset-env
  4. polifill

    • polifill 是什么? preset-env 遇到更新的语法时,比如promise, generator, symbole 等,就不工作了,所以需要polifill 来做些填充
    • @babel/polifill(webpack5 前, 很大): 现在安装polifill 会给出一个 deprecated 提示,同时给出一个文档(babeljs.io/docs/en/bab… ), 给出替代polifill 插件的插件, 这是webpack5想让我们按需配置,而不是引入所有的polifill
    • webpack5 后, 替代 @babel/polifill ,使用 core-js regenerator-runtime
    • useBuiltIns: 由于是给polifill 打补丁,所以参数配置在polifill 中(使用entry 时,还需要再index.js 中import core.js 和 regenerator-runtime, 具体可看babel)

    image.png

6. plugin 的一些注意点

八. browserslistrc

工作方式,通过.browserslistrc 设置浏览器兼容规则,实现兼容的一些插件,就会通过这些兼容规则,产出对应的兼容的代码, (安装webpack 的时候会自动安装 browserslist, 可通过在命令行中输入 npx browserslist 获取到当前项目 想兼容-利用插件的平台)

  • 如何实现兼容:babel, postcss(需要配合autoprefixer 模拟产出的网站:autoprefixer.github.io), postenv, babel 和postcss 进行转换时,会以browserslistrc为标准,决定是否对某些属性或特征进行转换
  • 兼容哪些平台 (网站:caniuse.com )

九. 打包的时间和内容分析

  • speed-measure-webpack-plugin (分析速度)
  • webpack-bundle-analyzer (打包后的大小分析)

十. 其他

0. 占位符

  • 在file loader 中使用参数, 给打包输出的文件命名 (使用了占位符) options: { name: 'img/[name].[hash:6].[ext]' }
  • 通用的占位符: image.png

1. webpack-dev-server 初始

  • webpack --watch + vscode 的live server
  • webpack.config.js {watch: true} + vscode 的live server
  • 改进空间:
  1. 某个文件改变,所有源代码都会重新编译
  2. 每次编译成功,都需要进行文件读写
  3. live server 不能实现模块刷新
  • 安装完成后, webpack serve(webpack 5 才行, webpack5 之前要写全)
  • 使用的好处是:
  1. 无需依赖 vscode 的live server
  2. 可以实现热更新
  3. 无需进行文件读写,每次更新都在内存中

2. webpack-dev-middleware

对打包过程做自由度很高的定制, 实现思路,开启一个服务, 将打包的代码交给这个服务。 image.png

3. HMR 功能的使用(Hot Module ReplaceMent)

webpack-dev-server 中已实现,只需要开启配置 devServer:{hot: true}, 并且需要在index.js 中,表示哪些模块需要热更新 if(module.hot){module.hot.accept(['./title'], ()=>{console.log('更新完后的操作')})} 开发阶段,还需要设置 target: 'web'

image.png

4. react 组件热更新

  • 上面的热更新功能只使用于js 模块,如果react 写在js 中,并且添加到了accept, component 里面的state更新将不会再触发界面的更新
  • jsx 文件需要用到 babel-loader 解析
  • react 组件的热更新之前是有个loader react-hot-loader , 但是对于新变需要用到一下两个依赖模块, 并且react 模块都不需要加入 module.hot.accept 中 npm install @pmmmwh/react-refresh-webpack-plugin react-refresh

image.png

image.png

5. vue 组件热更新

  • vue 文件需要用到 vue-loader 解析(vue3 使用 16版本, vue2 使用15或14)
  • 使用了vue-loader@14, vue 组件就默认的热更新
  • 使用了vue-loader@15 之后需要自己使用插件

image.png

6. output 中的path

output: { fileName: 'js/main.js', path: path.resolve(__dirname, 'dist') publicPath: '' }

  • path 产出到哪个目录下
  • publicPath 不写表示 '', publicPath 告诉html 怎么去找他里面加载的资源(域名 + publicPath + fileName, 比如将我们打包后的资源放置在cdn服务器下,html 中的路径就会添加publickPath前缀)

7. devServer 中的path

  • publicPath 不写表示'/'(表示当前服务所在的目录), 指定本地服务所在目录(就是生成的项目假装放到这个目录下,比如'/lg', 此时访问ip/lg 可以访问到html, 但是html 中的资源访问路径是output生成的)(资源是devServer生成的在/lg中,但是资源路径是output生成的在''中,所以html 无法通过路径访问到资源)
  • devServer 中的publicPath 要和 output 中的publicPath 相同,才可以在html 中通过路径访问到资源,
  • contentBase: 打包之后的资源如果依赖了其他资源(未打包资源等),此时就告知去哪找contentBase: path.resolve(__dirname, 'public')
  • watchContentBase: 观察contentBase中的属性是否发生变化

8. devServer 常用配置

  • hotOnly 界面上已输入的值不会改变
  • compress 压缩
  • historyApiFallback 当使用history 模式的时候用来让他重定向到index.html

9. proxy 代理设置(开发阶段)

  • target 目标地址
  • pathRewrite {"^/api", "x"} 把代码中api 开头的转换为以test开头去请求()
  • changeOrigin: true 修改host,对于有些限制host的网站有用

10. resolve 模块打包规则

  • extensions: [] 文件后缀数组
  • alias 别名对象

11. source-map 作用

  • mode 打包模式
  • devtool

12. devtool详细说明

[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

  • eval 打包后文件的eval 中包含//# sourceUrl=webpack://02_webpack_config_start/./src/utils.js (可以发现打包build后的错误信息可以正确找到对应的行和列, 但是起本地服务serve 后的错误信息却不能找到,因为他存储的是相对路径?)
  • source-map 生成了一个map 文件, 在打包后的文件中有这样一句话表示映射到map 文件 //# sourceMappingUrl=main.js.map(需要有babel-loader 才可看到列信息)
  • eval-source-map 生成一个map 文件数据,文件以base64的字符串塞入到打包后的文件的eval 中,/# sourceUrl=[module]\n//# sourceMappingUrl=data:application/json...(需要有babel-loader 才可看到列信息)
  • inline-source-map 生成一个map 文件数据,文件以base64的字符串塞入到打包后的文件的最后,//# sourceMappingUrl=data:application/json...(需要有babel-loader 才可看到列信息)
  • cheap-source-map 只提供错误行信息不提供列信息, 同时提供的行信息是经过转换之后的,中间的行可能被删除
  • cheap-module-source-map 只提供错误行信息不提供列信息, 但是提供的行信息就是源文件的,没经过转换的
  • hidden-source-map 有map 文件,但是打包文件中没有 sourceMappingUrl 的指向, 因此定位不到源文件。 用处(如果在生产环境中想要调试,并且源文件中并没有map文件,只需要把他放到生产环境下就可以调试了)
  • nosources-source-map 有map 文件,但是点击错误信息,但是无法定位到具体错误行 PS: 开发测试阶段一般使用cheap-module-source-map

13. ts-loader 编译 ts

和less-loader 依赖less 一样, ts-loader 依赖 typescript, ts 转换 为 js, 但是不能把polifill 进行填充,可以在编辑阶段提示语法错误

14. bable-loader 编译 ts

babel-loader + @babel/preset-typescript , 可以 ts 转换 为 js, 也可以把polifill 进行填充, 但是无法在编译阶段提示语法错误, 可以先执行 tsc --noEmit 命令,进行语法校验工作

15. 区分 生产开发环境

webpack.config.js: 通过package 的script 命令中传入--env production,在webpack.config.js 中 导出 的module.export = (env)=> {return {}} 可以获取到env.production = true babel.config.js: 通过 在webpack.config.js 的函数中设置 process.dev.NODE_ENV = 'production' , 可以在bable.config.js 中通过process.dev.NODE_ENV 区分 项目的模块文件: 通过在webpack.config.js 中的mode 中设置 'production', webpack 会自动把process.dev.NODE_ENV 设置为 'production' ,来供项目模块文件使用

16. 打包可能会生成LICENSE.txt

当打包的文件中依赖像loadsh, jquery 这样的库时,就会出现LICENSE.txt 这样的文件与他所打包在一起的文件同名,比如main.js 和 main.js.LiCENSE.txt, LICENSE.txt 就会里面的内容其实就是介绍库的, 如下图

image.png 如果希望看不到这些文件,可以使用插件 terser-webpack-plugin 该插件的作用就是压缩javascript 文件,其中有个extractComments的配置项可以决定是否将注释剥离到一个文件中,具体配置可看webpack 官方文档

17. 代码拆分方式

  • 使用 entry: './src/main.js' 打包成功之后会只输出一个 main.js ,如果文件中引入了lodash ,也会把lodash 打包进同一个文件
  • 使用 entry: {main: {import: './src/index.js', dependOn: ['lodash']}, lodash: 'lodash'}就会分别打包出 'main.js' 和 'lodash' 两个文件
  • splitChunks Optimization 把依赖的包拆出,具体看文档

18. import 动态导入配置

  • chunkFileName output 的配置项 设置名
  • chunkIds optimization 的配置项,可以设置chunk的 id 作为 chunkFileName 的[name][id]的占位符
  • 动态引用也可以通过 import(/*webpackChunkName: 'title' */ './title') 来设置 chunkFileName[name]的占位符
  • prefech import(/*webpackChunkName: 'title' */ /* webpackPrefetch: true */'./title') 将来某些导航下可能需要的资源 , 浏览器空闲时间加载
  • preload import(/*webpackChunkName: 'title' */ /* webpackPreload: true */'./title') 当前导航下可能需要资源, 当前需要加载

19. scope hoisting(作用域提升)

  • production 模式默认内置了
  • development 模式,在打包出的文件中,可以看到有几个文件的引用,每个文件都用闭包包起来,引用需要通过层层查找。new webpack.optimize.ModuleConcatenationPlugin() 这个就可以将作用域提升到主入口文件,两个文件同名函数会被改名
  • 这个插件底层是基于esmodule

20. resolve.mainFields

  • 当从 npm 包中导入模块时(例如,import * as D3 from 'd3'),此选项将决定在 package.json 中使用哪个字段导入模块

21. webpack 打包library

  • 设置'library: {name:'myLib', target: 'umd'}, 打包出一个js, 这个js 会以 "object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.myLib=o():e.myLib=o() 打头来判断这个脚本会是在哪个环境下使用
  • 引用(这块折腾了很久,尤其是第二点import 要注意使用babel时的属性)
    • 通过 script引用, 可以判断到环境是浏览器环境,需要使用 window.myLib引用
    • 通过 import * as myLib from 'url'引用, 可以判断到"object"==typeof exports&&"object"==typeof module这个为true,意思是commonjs 环境,可以直接通过myLib 引用, (PS: 这边起项目的时候,有时候会发现myLib 为 一个空对象, 这个是因为使用了babel(如果不使用babel不会有问题),使用 @babel/preset-env 预设时,没有设置属性 module 为 'umd' 或 ‘commonjs’,看打包源码可以发现,没有设置的时候,引用的key 对应的方法中的exports 形参 变成了其他名字,而设置了之后,exports的形参就为exports )