在使用 gulp 构建的 Webpack 包中导出 Typescript 函数,浏览器中的空对象

Posted

技术标签:

【中文标题】在使用 gulp 构建的 Webpack 包中导出 Typescript 函数,浏览器中的空对象【英文标题】:Exporting Typescript function in Webpack bundle built with gulp, empty object in browser 【发布时间】:2017-12-11 10:02:36 【问题描述】:

我正在尝试从 typescript 构建一个带有导出的 js 包,我可以直接从内联脚本调用它,但我似乎无法让它工作。

我有一个这样的 Typescript 源文件:

export namespace Init 
    export function index() 
        // do some things
    


export function blahblah()  console.log('blahblah') 

这与同一文件夹 src/ts/*.ts 中的一些其他来源并列。我的 webpack.config.js 看起来像这样:

'use strict';

module.exports = 
    context: __dirname,
    output: 
        filename: 'bundle.js',
        library: 'bitthicket',
    ,
    devtool: 'sourcemap',
    resolve: 
        extensions: [ '.ts', '.tsx', '.js' ]
    ,
    module: 
        rules: [
             test: /\.tsx?$/, exclude: /node_modules/, loader: 'ts-loader' 
        ]
    

最后,我的 gulpfile.js 看起来像这样:

var gulp = require('gulp')
var gutil = require('gulp-util')
var plumber = require('gulp-plumber')
var watch = require('gulp-watch')
var sass = require('gulp-sass')
var ts = require('gulp-typescript')
var clean = require('gulp-clean')
var webpack = require('webpack')
var webpack_config = require('./webpack.config.js')
var webpack_stream = require('webpack-stream')


let _sass = () => 
    gulp.src('src/css/**/*.scss')
        .pipe(plumber())
        .pipe(sass())
        .pipe(gulp.dest('static/css'))
        .on('end', () => gutil.log('_sass: done'))

let _webpack = () => 
    gulp.src('src/ts/**/*.ts')
        .pipe(plumber())
        .pipe(webpack_stream(webpack_config, webpack))
        .pipe(gulp.dest('static/js'))
        .on('end', () => gutil.log('_webpack: done'))

gulp.task('build:sass', _sass)
gulp.task('clean:sass', () => gulp.src('static/css/**/*').pipe(clean()))
gulp.task('watch:sass', () => watch('src/css/**/*.scss', () => _sass()))

gulp.task('build:webpack', _webpack)
gulp.task('clean:ts', () => gulp.src('static/js/**/*').pipe(clean()))
gulp.task('watch:webpack', () => watch('src/ts/**/*.ts', () => _webpack()))

gulp.task('watch', ['watch:sass', 'watch:webpack'])
gulp.task('clean', ['clean:sass', 'clean:ts'])
gulp.task('build', ['build:sass', 'build:webpack'])
gulp.task('default', ['clean', 'build'])

html 文件中:

<script src="bundle.js" async></script>
<script>window.onload = function()  console.log(bitthicket); </script>

据我所知,正在发生的事情是 webpack 正在获取源文件的管道列表作为入口文件,就好像它们被放置在命令行上一样 webpack src list bundle.js。但是我已经设置了我的library 输出选项,并且bitthicket 变量确实被设置了,但它是一个空对象。 Init.index怎么了?

编辑:我将 export 关键字添加到 Init 命名空间,以及添加到 init.ts 的普通函数以查看会发生什么 - 但生成的对象仍然没有这些函数。

这是生成的 webpack 引导程序参数:

/***/ ),
/* 1 */
/***/ (function(module, exports, __webpack_require__) 

"use strict";

exports.__esModule = true;
var _ = __webpack_require__(2);
var Init;
(function (Init) 
    function index() 
        Nav.attachNavbarScrollWatcher();
        document.addEventListener('scroll', function (event) 
            var articles = document.querySelectorAll('.featured column.summary article');
            var visibleArticle = _.find(articles, function (el)  return Util.isElementInViewport(el); );
            console.log("0 just became visible", visibleArticle);
        );
    
    Init.index = index;
)(Init = exports.Init || (exports.Init = ));
function blahblah() 
    console.log('blahblah');

exports.blahblah = blahblah;


/***/ ),

如您所见,exports.blahblahexports.Init.index 分配在此块中 - 但我在浏览器中返回的对象如下所示:

【问题讨论】:

【参考方案1】:

我的问题的真正答案是

你还模块吗,兄弟?

我只是完全误解了 typescript 调用命名空间和模块之间的关系,以及 webpack 认为模块是什么。

在这个徒劳的练习之后,我什至不确定 Typescript 命名空间有什么意义,除非你有一个多阶段的构建过程,你使用 tsctsconfig.json 来创建多个转译包,这些包将稍后被 Webpack 等其他加载器重新捆绑。

总之,言归正传:

Typescript“命名空间”对 Webpack 毫无意义(更具体地说,ts-loader:参见TypeStrong/ts-loader#193)。 Webpack 无法遍历 namespace 依赖项,因此您最终会在包中找到未定义的符号,这意味着 webpackBootstrap 函数也不知道如何以正确的顺序加载内容。我的包中的入口点有点像这样:

/* 0 */
/***/ (function(module, exports, __webpack_require__) 
__webpack_require__(1);  // <-- actual entry point, exports are lost
__webpack_require__(2);
exports = __webpack_require__(4); // <-- not entry point, nothing is exported here anyway
/***/ ),
...

Webpack(和ts-loader)需要一种可以理解的模块形式,以便引导程序正确加载内容。

我仍在使用 Typescript 命名空间作为结构,但我使用 exporting 它并使用 import 表示对其他 Typescript 模块的依赖:

import * as _ from 'lodash'
import * as Nav from './nav'
import * as Util from './util' 

export namespace Init 
    // ...

主要是将依赖关系表达为es2015风格的import/exports。

【讨论】:

以上是关于在使用 gulp 构建的 Webpack 包中导出 Typescript 函数,浏览器中的空对象的主要内容,如果未能解决你的问题,请参考以下文章

迁移到 Webpack 2 后,gulp 或 webpack-stream 导致 webpack 构建失败

前端构建工具Gulp.js 你知多少..(webpack/gulp/grunt)

深入使用webpack构建vue.js单页应用

使用ES6+Vue+webpack+gulp构建新一代Web应用

gulp+webpack配置

第718期想要设计gulp & webpack构建系统?看这儿!