关于webpack5中library字段的几个疑问

webpack中library的文档地址

我在文件src/index.ts写了这样一个函数

function hello(name?: string) {
  console.log(`hello ${name}`);
}

export default {hello};
export {hello};

因为我想在使用的时候做到

import MyLib from 'my-lib';
import {hello} from 'my-lib';
Mylib.hello();
hello();

webpack.config.js

module.exports = {
  // xxx
  output: {
    // xxx
    library: {
      name: 'MyLib',
      type: 'umd'
    }
  },
  resolve: {
    extensions: ['.js', '.ts']
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: ['babel-loader', 'ts-loader'],
        exclude: /node_modules/
      }
    ]
  }
};

打包出来的文件是这样的

(function webpackUniversalModuleDefinition(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if(typeof define === 'function' && define.amd)
        define([], factory);
    else if(typeof exports === 'object')
        exports["MyLib"] = factory();
    else
        root["MyLib"] = factory();
})(self, function() {
    // xxxx
});

然后使用npm link使用的时候就报错了

// SyntaxError: The requested module 'xxx' does not provide an export named 'default'
// SyntaxError: The requested module 'xxxx' does not provide an export named 'hello'

我理解的type: 'umd'的情况下会使用name: 'MyLib'定义我的模块,那我就可以直接使用MyLib.hello?或者我有把具体的函数导出,那也可以使用具体的hello
请教一下大佬这一块怎么去理解?

阅读 2.9k
2 个回答

解决了,问题关键确实在于librarytype字段,当typeumd的时候,这是文档的解释

这将在所有模块定义下暴露你的库, 允许它与 CommonJS、AMD 和作为全局变量工作。

其实本质是我没有弄懂CommonJS、AMD这几种方式的区别,直接先说最后一种作为全局变量工作,其实从webpack打包的代码就应该看出来的,是一个iife函数,所以其实直接import进来就可以

import 'my-lib'

console.log(window.MyLib) // 全局下就会有一个我在上面命名的name变量,里面就是我所需要的东西

而下面的内容就是我的一点理解了,如有有误的地方可以指出来,因为毕竟问题就出在这里
CommonJs方式:CommonJs是用在服务器端的,如果在我这个里面应该是如下使用?

let myLib = require('my-lib');
myLib.hello('xxx')

AMD方式:AMD就是使用在浏览器端的方式,如下是文档解释,可以理解为直接用是不行的,需要一个能兼容的库例如RqeuireJs等。

AMD module 要求入口 chunk(例如,第一个通过<script>标签加载的脚本)使用特定的属性来定义, 例如definerequire,这通常由RequireJS或任何兼容的loader(如almond)提供。否则,直接加载产生的AMD bundle将导致一个错误,如define is not defined

使用的示例应该是这样?

require(['my-lib'], function (myLib) {
  myLib.hello('xxx')
});

那么话说回来,需要实现我问题中的那种使用该怎么去设置类型呢?我在文档发现了另一个类型module

输出 ES 模块。
然而该特性仍然是实验性的,并且没有完全支持,所以请确保事先启用 experiments.outputModule。
module.exports = {
  // …
  experiments: {
    outputModule: true,
  },
  output: {
    library: {
      // do not specify a `name` here
      type: 'module',
    },
  },
};

直接贴过来吧,这确实就是我提问的想用的方式,虽然还是处于实验性的,但是试验发现还是没问题的,本来想说这样折腾就用rollup多好,最后想想还是说菜鸡没有理由吧。

这里的问题在于你的写法不符合 ESM。

如果你想用 import {hello} from 'my-lib',那么你应该在库里面 export hello,ESM 不支持直接解构导入的库。

应该写成:

import MyLib from 'my-lib';

const {hello} = MyLib;
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题