使用 Browserify 或 Webpack 打包后如何访问“公共”成员

8

我有一个定义了一个名为App类的test.js脚本,它是由HTML文件加载的,一切正常。

当我使用browserify或webpack从test.js创建一个testBundle.js捆绑包时,testBundle.js中的App类似乎不再被定义。

我应该如何编写代码或给browserify哪些选项以便在捆绑后像以前一样从捆绑包中定义并使用App

打包后我得到的错误是:

Uncaught ReferenceError: App is not defined
文件如下:
<html>
   <script src="testBundle.js"></script>

   <script>
       var app = new App();
   </script>
</html>

test.js:

'use strict';

class App {
    constructor() {
        console.log("App ctor")
    }
}

构建打包文件的命令:

browserify -t [ babelify --presets [ es2015 ] ] test.js  -o testBundle.js 

在查看bundle内部时,我发现该应用实际上是私有的。

testBundle.js

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var App = function App() {
    _classCallCheck(this, App);

    console.log("App ctor");
};


},{}]},{},[1]);

所有这些都使用来自浏览器的JavaScript,ES6。


抱歉,但我相信(希望)有更好的解决问题的方法,我将开始悬赏。 - cdarwin
3个回答

11

您正在尝试在全局上下文中访问App。但是,App默认情况下不会在全局范围内提供。Node.js使用模块,Browserify尊重模块提供的封装性。当使用Browserify或Webpack等工具时,通常会有一个或多个入口点模块(即文件),这些模块使用模块导入/require()来访问其他模块。

但是,如果您想要能够在浏览器中的全局上下文中访问App,则可以将对App类的引用分配给window的属性,在test.js中:

例如:

window.App = App;
或者
Object.assign(window, { App });

这个可行,但如果我有其他的类,我就得在每个脚本末尾使用windows.MyClass = MyClass来“导出”每一个类吗?我希望有另一种解决方案。 - cdarwin
从其他模块访问实体的正常方式是使用import/export或require()。您想要使所有类都全局可访问,这是不应该使用Browserify或Webpack的方式。您可能不需要在html中有任何单独的<script></script>,而应该有一个入口js文件,它导入/需要依赖的脚本。这应该是您指定给Browserify或Webpack的入口文件。 - fvgs
你说“应该有一个入口js文件来导入/需要脚本”,但我正在使用浏览器中的JavaScript,无法使用import或require... - cdarwin
你知道其他打包工具不需要使用 require/import 并将打包的元素导出到全局作用域中吗? - cdarwin
1
你所描述的是将多个JS文件合并成一个JS文件。肯定有许多工具可以做到这一点,不仅仅是针对JS。效果与在HTML中使用<script src="...">包含每个单独的JS文件相同。或者,如果你的代码不多,你可以将它们全部放在一个文件中,因此无需合并JS。但最干净和推荐的处理多个JS文件的方法是将它们视为模块,并使用诸如Webpack、Rollup或Browserify等模块打包工具进行捆绑。 - fvgs
显示剩余2条评论

1

基本上,您想要做的是创建一个库而不是常规捆绑包。如果您使用webpack,可以指定要将输出设置为库,这将使其通过命名空间在全局范围内可用,类似于jQuery。

// relevant part of your webpack config
// from webpack docs
{
  output: {
    // export itself to a global var
    libraryTarget: "var",
    // name of the global var: "Foo"
    library: "Foo"
  }
}

然后,您可以通过Foo调用所有函数:
var app = new Foo.App()
var somethingElse = Foo.doSomethingElse()

文档和示例:https://webpack.github.io/docs/library-and-externals.html#examples


0

Webpack或Browserify将您的脚本捆绑在某个上下文中,因此您只能在捆绑的脚本中的某个位置联系类或函数。因此,当您在HTML中添加另一个脚本时,它无法访问这些捆绑脚本的上下文。如果您想要访问App类,据我所知,您可以将新脚本(现在只是创建一个新的App)导入/导出到test.js中。


你能更明确地说明“导入/导出新脚本”的意思吗? - cdarwin
基本上,我会避免在HTML中使用<script></script>添加新脚本,并使Webpack的入口文件包含所有脚本,比如将App实现在另一个文件app.js中,并将其导入到测试文件test.js(即入口文件)中。 - Jangmi Jo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接