从HTML脚本标签外部调用webpack打包后的代码

174

假设我有一个类,就像这样(用typescript编写),并且我使用webpack打包它成bundle.js

export class EntryPoint {
    static run() {
        ...
    }
}

我会在我的index.html文件中包含这个捆绑包,但是我还想调用那个静态方法。

<script src="build/bundle.js"></script>
<script>
    window.onload = function() {
        EntryPoint.run();
    }
</script>

然而,在这种情况下EntryPoint未定义。那么我如何从另一个脚本调用捆绑的Javascript呢?

添加: Webpack配置文件


请添加您的Webpack配置。我认为在你的onload方法中缺少类似于 var EntryPoint = require('EntryPoint') 的东西。 - MartyIX
3
我已经添加了我的配置。的确需要类似于require的东西,但和下面的import一样,它会显示“未定义require”。我试图使用来自纯JavaScript的打包内容,难道不需要再次使用某个框架才能使用require吗?但我正在尝试避免这种情况。希望有意义。 - Raven
9个回答

178

看起来你想将webpack捆绑包作为公开。您可以配置webpack,在您自己的变量中以全局上下文公开您的库,例如EntryPoint

我不知道TypeScript,因此示例使用普通JavaScript。但这里的重要部分是webpack配置文件,特别是output部分:

webpack.config.js

module.exports = {
  entry: './index.js',
  output: {
    path: './lib',
    filename: 'yourlib.js',
    libraryTarget: 'var',
    library: 'EntryPoint'
  }
};

index.js

module.exports = {
  run: function () {
    console.log('run from library');
  }
};

那么您将能够按照您的期望访问您的库方法:

<script src="lib/yourlib.js"></script>
<script>
  window.onload = function () {
    EntryPoint.run();
  };
</script>

查看具有实际代码的gist


21
我们有多个入口点,因此在输出部分,我改为使用 library: ["GlobalAccess", "[name]"]。这将使变量成为一个对象,其中包括每个入口点的成员:GlobalAccess.EntryPointFoo、GlobalAccess.EntryPointBar等等。 - John Hatton
4
这适用于 npm run build,但在使用 webpack-dev-server 的开发环境中不起作用。我的导出入口点是一个空对象。有任何想法吗? - nkint
1
如果是这种情况该怎么办:entry: { page1: [ 'module1.js', 'module2.js' ], page2: 'module3.js' },@JohnHatton 的建议似乎就不起作用了。我可以访问page1.module2,但无法访问page1.module1。它似乎只使用了最后一个模块。 - sheamus
2
按照步骤进行了操作,更改了配置并重新构建,但仍然出现“未捕获的ReferenceError:EntryPoint未定义”的错误。 - user889030
2
我已经在babel + webpack v3.10.0中找到了一个类似的例子,通过将index.js更改为export function run() {}而不是module.exports = ...使其正常运行。 - dworvos
显示剩余7条评论

63

我设法让它正常工作,没有进一步的 webpack.config.js 修改,只需使用 import 语句,我从我的 main/index.js 文件中调用:

import EntryPoint from './EntryPoint.js';
window.EntryPoint = EntryPoint;

输入图像描述

供参考,这是我的weback.config.js文件。

起初我尝试使用require来实现同样的效果,但它将模块包装器分配给了window.EntryPoint,而不是实际的类。


3
可以不用 ES6 来完成这个任务吗?否则,我会遇到 "Uncaught SyntaxError:Unexpected token import" 的错误。你的 index.js 文件是否已经打包好了(我看到它是入口点,但不确定)? - Raven
4
我理解你的意思是,你想访问一个被打包在一个不属于这个包的脚本中的东西。就像这个包是一个库,而你试图从外部访问它的方法一样。这是可能的吗? - Raven
4
这个解决方案非常简单,我为自己没有在问题出现时就想到它而感到羞愧。 - cav_dan
2
我被这个问题卡了好几个小时。本来想把脚本移到我的捆绑包里,但那样会引起更多的问题。感谢你提供简单的答案!! - Stephen Agwu
1
这对我解决了问题。无论您使用“require”还是“import”,关键是“window.EntryPoint = EntryPoint”。这将EntryPoint强制放入全局上下文中(命名空间污染,喘气!),从而允许您从脚本标记内引用它。(毕竟这就是整个重点!) - Duncan
显示剩余5条评论

23

在我的情况下,我能够通过在创建函数时将函数写入窗口来从另一个脚本中调用捆绑的JavaScript中的函数。

// In the bundled script:
function foo() {
    var modal = document.createElement('div');
}
// Bind to the window
window.foo = foo;
// Then, in the other script where I want to reference the bundled function I just call it as a normal function
<button onClick="window.foo()">Click Me</button>

我无法使用 Babel,所以这对我起作用了。


这是非常整洁的解决方案。 - Teoman shipahi
不幸的是,它与TS不兼容。但确实,这本来是一个很好的解决方案 :-) - rlegendi
你是不是只因为Babel无法工作才要这样做? - chackerian

2

WEBPACK.CONFIG.JS

1. 使用UMD

module.exports={
            mode:'development',
            entry:'./yourentry.js',
            output:{
                path:path.resolve(__dirname,"dist"),
                filename:'main.js',
                publicPath:'/dist/',
                libraryTarget:'umd', 
                library:'rstate',
                umdNamedDefine: true,
                libraryExport: 'default' 
            }
    }

index.html

<script src="dist/main.js"></script>
<script>
  window.onload = function () {
  rstate()=>{}
</script>

main.js

export default function rstate(){
console.log("i called from html")
}

2.使用 VAR

module.exports={
            mode:'development',
            entry:'./yourentry.js',
            output:{
                path:path.resolve(__dirname,"dist"),
                filename:'main.js',
                publicPath:'/dist/',
                libraryTarget:'var', 
                library: 'EntryPoint'
            }
    }

index.html

<script>
  window.onload = function () {
  EntryPoint.rstate()=>{}
</script>

main.js

module.exports={
    rstate=function(){
        console.log("hi module")
    }
}

3.使用AMD作为库时,我们可以像这样使用(适用于那些想要创建库的人)

define(['jquery', './aux-lib.js'], function ($) { ..(1).. });

2
我遇到了类似的挑战,我想为旅程中的多个页面创建一个捆绑包,并希望每个页面都有自己的代码入口点,而不需要为每个页面创建单独的捆绑包。
这是我的方法,与Kurt Williams非常相似,但从略微不同的角度,也不需要更改webpack配置: :「旅程主控文件」
import { getViewData } from './modules/common';
import { VIEW_DATA_API_URL } from './modules/constants';
import { createLandingPage, createAnotherPage } from './modules/components/pageBuilder';

window.landingPageInit = () => {
    getViewData(VIEW_DATA_API_URL).then(viewData => {
        createLandingPage(viewData);
    });
};

window.anotherPageInit = () => {
    getViewData(VIEW_DATA_API_URL).then(viewData => {
        createAnotherPage(viewData);
    });
};

// I appreciate the above could be one liners,
// but readable at a glance is important to me

然后在html页面的末尾,我会展示如何调用这些方法的例子:

最初的回答:

<script src="/js/JourneyMaster.js"></script>
<script>window.landingPageInit();</script>

1
This took me forever to figure out as the accepted answer wasn't working for me. Just make sure the function name is the same as the library in the config and it's bundled with the config specified -- npx webpack --config webpack.config.js --mode=development -- hopefully this saves people a few hours.

index.js (需要捆绑的函数) >>

function EntryPoint() {
    console.log('called from bundle');
}

module.exports = EntryPoint;

webpack.config.js >>

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
        libraryTarget: 'var',
        library: 'EntryPoint'
    },
};

start.html(调用打包函数的地方)>>

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Azure SDK Storage Example</title>
    <script type="text/javascript" src="./dist/main.js"></script>
  </head>
  <body>
      <h1>Azure SDK Storage Example</h1>
  </body>
</html>

<script>
 EntryPoint();
</script>

0
也许这是我自己的一些冒名顶替综合症,但我认为“真正”的程序员会对我的回答感到不满。无论如何,我发现这个解决方案最适合在我的业余项目中实现时间上的务实:
将您的JS函数声明从以下方式更改:
function renderValue(value) {

到:

global.renderValue = function(value) {

当然,您会像任何其他文件一样要求require('path/to/your_custom_js')
我在这里找到了这个答案: https://www.fastruby.io/blog/rails/webpack/from-sprockets-to-webpacker.html

0
许多答案到目前为止都是正确的,只需要澄清一点:直到库被声明并构建后,Webpack 才能识别它。在创建库后,应该在继续使用 npm start 之前立即使用 npm run build。 至少对我来说是这样,仅使用 webpack。

-4

App.ts:

namespace mytypescript.Pages {

        export class Manage {

     public Initialise() {
     $("#btnNewActivity").click(() => {
                    alert("sdc'");
                });
        }
    }
}

mypage.html:

 <input class="button" type="button" id="btnNewActivity" value="Register New Activity" />

 <script type="text/javascript">
    var page = new mytypescript.Pages.Manage();
    page.Initialise();
</script>

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