问题与答案
一. 简述前端兼容性的解决方案及不同工具的使用(CSS及JS)
1. 针对css
- 不同的浏览器中都有默认的一些css 样式,比如
margin,padding等,各浏览器不同。- 解决方法: 使用css reset 来重置浏览器的默认样式
- 针对不同浏览器,某些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
- 不同浏览器的一些兼容写法,比如监听或者获取大小等监听,可以使用jquery 解决
- 对于遇到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
- 如果自己有cdn服务器
- 将静态文件放置在服务器上
- 设置publicPath 告诉html 服务器所在地址,在打包后html引用的脚本路径就会加上服务器前缀
- 如果自己没有cdn服务器
- externals: {lodash: '_'}, 将第三方包排除,不进行打包
- 在html 中引入第三方包 的cdn 地址
2. 打包/使用 dll 库
对不常变动的,体积较大的库使用DllPlugin 动态链接库进行打包
- 设置入口为想要打包的库, 使用 webpack.DllPlugin 进行打包出js 和 manifest.json 文件
- 在需要打包的项目中, 使用webpack.DllReferencePlugin ,把dllplugin 打包出来的manifest 和 js 关联起来
- 在需要打包的项目中,使用 externals 将第三方包移除,不进行打包
- 在模板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 结合使用
常用的网站
- package.json: docs.npmjs.com/cli/v8/conf…
- terser: https://github.com/terser/terser
- 兼容相关
webpack 打包概述
一. 怎么让webpack工作
- 全局安装webpack 和 webpack-cli 后, 在命令行中执行webpack 命令,(webpack 会默认将src/index.js 作为入口文件)(缺点:全局安装,每个人安装的版本不一样)
- 局部安装webpack 和 webpack-cli 后, 在命令行中执行 npx webpack 命令,(npx 会找到node_module 下面 .bin 目录下面的 webpack 文件执行)(缺点:在需要修改一些参数的时候,每次启动的命令行太长, 比如每次需要输入 npx webpack --entry ./src/main.js)
- 局部安装webpack 和 webpack-cli 后, 在package.json 中, 的scripts 中,添加 "build": "webpack --entry ./src/main.js", 直接在命令行中执行命令 npm run build (缺点:无法做过于复杂的配置)
- 局部安装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的打包流程
- 创建一个run.js 文件
- 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())}) - 执行 node run.js 命令,在vscode 调试界面中进行调试,后续,将
require('webpack')中的webpack 改成自己手写的库可进行验证
三. 初始化一个 js 项目需要配置什么
- 需要的最基础的依赖
- babel, babel-loader, @babel/core @babel/preset-env
- html-webpack-plugin
- webpack, webpack-dev-server, webpack-merge, webpack-cli
- 兼容需要的依赖与配置(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 }
- 模块热替换功能需要的依赖与配置
- devServer 设置 hot: true
- 在入口文件添加哪些模块开启热更新的配置 if(module.hot){module.hot.accept(['./title'], ()=>{console.log('更新完后的操作')})}
- 如果不生效可能是项目项目的.browserslistrc 冲突了,所以可以在webpack 中设置target: 'web',在开发阶段屏蔽掉 browserslistrc
四. 初始化一个react 项目需要配置什么
- 需要的最基础的依赖
- react, react-dom
- babel, babel-loader, @babel/core @babel/preset-env @babel/preset-react
- 需要 初始化一个 js 项目 最基础的依赖
- 兼容需要的依赖与配置(polifill 兼容性补充 兼容性补充 @babel/preset-env)
- 方式和初始化一个 js 项目的方式相同
- 模块热替换功能需要的依赖与配置
- 对于模块文件
- webpack.config.js 中需要使用插件@pmmmwh/react-refresh-webpack-plugin
- babel.config.js 中需要使用插件 react-refresh/babel
- 对于工具文件
- 工具文件热更新的方式 和 初始化一个 js 项目 的方式相同
- 模块文件不能像被module.hot 引入,否则就会造成模块文件state改变,但是视图更新不了
- 对于模块文件
五. 初始化一个vue 项目需要配置什么
- 需要的最基础的依赖 -vue, vue-template-compiler, vue-loader
- 兼容需要的依赖与配置(polifill 兼容性补充 兼容性补充 @babel/preset-env)
- 方式和初始化一个 js 项目的方式相同
- 模块热替换功能需要的依赖与配置
- 对于 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 :
- 行内的loader
- 固定语法:loader + 英文! , 多个loader 用!分隔,就行,如下 import 'css-loader! ./login.css '
- 配置文件的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
-
css-loader
- 将css语法转换为js 语法
-
style-loader
- 将转换后的css 挂载到html 中去
-
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
-
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']}
-
file-loader
- img src,可以使用import x from 'x' , 或者 require('图片资源')
- 当使用requier('图片资源')方式导入图片时,有两个注意事项
- webpack4 引用文件的时候 require('x') 就可以拿到文件
- webpack5 需要使用require('x').default, 或者在 file-loader 中使用 options: {esModule: false}
- 当使用requier('图片资源')方式导入图片时,有两个注意事项
- img background , 使用url(图片资源)
- 在被 css-loader 进行转换时,会将他转换为 require(), 这个时候会发现图片加载不出来,
- 因为require 会将他转为 es module , 所以我们需要在配置 css-loader 时,需要设置参数options: {esModule: false}, 告诉他不要返回 es module , 直接返回资源
- img src,可以使用import x from 'x' , 或者 require('图片资源')
-
url loader
- url-loader 的作用是把图片转换成base64, 内嵌在文件中,可以减少请求次数,但是增加了请求体积,有可能增加首屏请求时间
- file-loader 的作用是将资源拷贝到指定目录,分开请求
- url-loader 的内部也可以 调用file-loader
- 最佳实践: 使用limit: 2 * 1024 (2kb), 当小于指定大小时,才转成base64, 大于指定大小,则在url-loader内部调用file-loader
-
webpack 5 中的asset
- 常用的配置
- 具体的使用:
-
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 使用中的一些注意点
- css-loader 将当前的css 语法转换为当前js可以使用的模块的类型,但并不能把样式放到界面使用, 如果想要在界面上看到样式变化,还需要使用style-loader
- 当多个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
-
html-webpack-plugin
-
webpack.DefinePlugin
-
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
-
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)
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]' } - 通用的占位符:
1. webpack-dev-server 初始
- webpack --watch + vscode 的live server
- webpack.config.js {watch: true} + vscode 的live server
- 改进空间:
- 某个文件改变,所有源代码都会重新编译
- 每次编译成功,都需要进行文件读写
- live server 不能实现模块刷新
- 安装完成后, webpack serve(webpack 5 才行, webpack5 之前要写全)
- 使用的好处是:
- 无需依赖 vscode 的live server
- 可以实现热更新
- 无需进行文件读写,每次更新都在内存中
2. webpack-dev-middleware
对打包过程做自由度很高的定制, 实现思路,开启一个服务, 将打包的代码交给这个服务。
3. HMR 功能的使用(Hot Module ReplaceMent)
webpack-dev-server 中已实现,只需要开启配置 devServer:{hot: true}, 并且需要在index.js 中,表示哪些模块需要热更新
if(module.hot){module.hot.accept(['./title'], ()=>{console.log('更新完后的操作')})}
开发阶段,还需要设置 target: 'web'
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
5. vue 组件热更新
- vue 文件需要用到 vue-loader 解析(vue3 使用 16版本, vue2 使用15或14)
- 使用了vue-loader@14, vue 组件就默认的热更新
- 使用了vue-loader@15 之后需要自己使用插件
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 就会里面的内容其实就是介绍库的, 如下图
如果希望看不到这些文件,可以使用插件
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 )
- 通过