2016-04-03 16 views
19

Tôi đang thử Webpack và đang thử hướng dẫn trong this tutorial, cung cấp hoặc thực hiện một số tùy chỉnh.Lỗi không mong muốn "Lỗi không xác định Loại lỗi: XXX không phải là hàm tạo" lỗi với Babel và ES6

Đây là mã đơn giản, thực sự, nhưng tôi khá bối rối về lỗi này và cảm thấy đây là điều ngớ ngẩn mà tôi đã bỏ lỡ.

tôi xác định hai ES6 lớp, mỗi tương ứng với một mẫu tay lái, và entrypoint ứng dụng của tôi có nghĩa vụ phải thay thế HTML giữ chỗ trong tệp chỉ mục theo nội dung:

Entrypoint:

import './bloj.less' 

// If we have a link, render the Button component on it 
if (document.querySelectorAll('a').length) { 
    require.ensure([],() => { 
     const Button = require('./Components/Button.js'); 
     const button = new Button('9gag.com'); 

     button.render('a'); 
    }, 'button'); 
} 

// If we have a title, render the Header component on it 
if (document.querySelectorAll('h1').length) { 
    require.ensure([],() => { 
     const Header = require('./Components/Header.js'); 

     new Header().render('h1'); 
    }, 'header'); 
} 

Index:

<!DOCTYPE html> 
<html> 
<head> 
</head> 
<body> 
    <h1>My title</h1> 
    <a>Click me</a> 

    <script src="build/bloj.js"></script> 
</body> 
</html> 

Button:

import $ from 'jquery'; 
import './Button.less'; 

export default class Button { 

    constructor(link) { 
     this.link = link; 
    } 

    onClick(event) { 
     event.preventDefault(); 
     alert(this.link); 
    } 

    render(node) { 
     const text = $(node).text(); 
     var compiled = require('./Button.hbs'); 

     // Render our button 
     $(node).html(
      compiled({"text": text, "link": this.link}) 
     ); 

     // Attach our listeners 
     $('.button').click(this.onClick.bind(this)); 
    } 
} 

Tiêu đề:

import $ from 'jquery'; 
import './Header.less'; 

export default class Header { 
    render(node) { 
     const text = $(node).text(); 
     var compiled = require('./Header.hbs'); 

     // Render the header 
     $(node).html(
      compiled({"text": text}) 
     ); 
    } 
} 

Đáng buồn thay, nó không hoạt động, và tôi nhận được cả các lỗi khi hiển thị trang:

Uncaught TypeError: Header is not a constructor 
Uncaught TypeError: Button is not a constructor 

gì có thể Tôi bị mất tích?

Dưới đây là cấu hình webpack của tôi:

var path = require('path'); 
var webpack = require('webpack'); 
var CleanPlugin = require('clean-webpack-plugin'); 
var ExtractPlugin = require('extract-text-webpack-plugin'); 

var production = process.env.NODE_ENV === 'production'; 
var appName = 'bloj'; 
var entryPoint = './src/bloj.js'; 
var outputDir = './build/'; 
var publicDir = './build/'; 

// ************************************************************************** // 

var plugins = [ 
    //new ExtractPlugin(appName + '.css', {allChunks: true}), 
    new CleanPlugin(outputDir), 
    new webpack.optimize.CommonsChunkPlugin({ 
     name:  'main', 
     children: true, 
     minChunks: 2 
    }) 
]; 

if (production) { 
    plugins = plugins.concat([ 
     new webpack.optimize.DedupePlugin(), 
     new webpack.optimize.OccurenceOrderPlugin(), 
     new webpack.optimize.MinChunkSizePlugin({ 
      minChunkSize: 51200 // 50ko 
     }), 
     new webpack.optimize.UglifyJsPlugin({ 
      mangle: true, 
      compress: { 
       warnings: false // Suppress uglification warnings 
      } 
     }), 
     new webpack.DefinePlugin({ 
      __SERVER__:  false, 
      __DEVELOPMENT__: false, 
      __DEVTOOLS__: false, 
      'process.env': { 
       BABEL_ENV: JSON.stringify(process.env.NODE_ENV) 
      } 
     }) 
    ]); 
} 

module.exports = { 
    entry: entryPoint, 
    output: { 
     path:  outputDir, 
     filename: appName + '.js', 
     chunkFilename: '[name].js', 
     publicPath: publicDir 
    }, 
    debug: !production, 
    devtool: production ? false : 'eval', 
    module: { 
     loaders: [ 
      { 
       test: /\.js/, 
       loader: "babel", 
       include: path.resolve(__dirname, 'src'), 
       query: { 
        presets: ['es2015'] 
       } 
      }, 
      { 
       test: /\.less/, 
       //loader: ExtractPlugin.extract('style', 'css!less') 
       loader: "style!css!less" 
      }, 
      { 
       test: /\.html/, 
       loader: 'html' 
      }, 
      { 
       test: /\.hbs/, 
       loader: "handlebars-template-loader" 
      } 
     ] 
    }, 
    plugins: plugins, 
    node: { 
     fs: "empty" // Avoids Handlebars error messages 
    } 
}; 

Trả lời

34

What could I be missing?

Babel gán xuất khẩu mặc định cho default tài sản. Vì vậy, nếu bạn sử dụng require nhập module ES6, bạn cần truy cập vào default tài sản:

const Button = require('./Components/Button.js').default; 
+0

Đó là những gì nó đã được. Tôi sẽ chỉnh sửa câu hỏi cho phù hợp. Rất cám ơn :) –

+0

bạn có thể sử dụng 'export var __useDefault = true;' và sau đó bạn không cần '.default' – alfonsob

+0

@alfonsob thay đổi thông số cấu hình giống như cách đi. Nhưng ở đâu? Tôi đang chạy vào một cái gì đó tương tự tại http://stackoverflow.com/questions/39510407/babel-at-fault-for-uncaught-typeerror-in-es2015-code –

5

Bạn chỉ có thể đặt export var __useDefault = true; chỉ sau khi xuất lớp của bạn.

export default class Header { 
... 
} 
export var __useDefault = true; 
+6

Bạn có thể thêm giải thích về cách thức hoạt động này không? – wiktus239

7

Tôi nhận thấy rằng bạn đã có câu trả lời. Tuy nhiên tôi đã có một vấn đề tương tự mà tôi tìm thấy một câu trả lời. Bắt đầu câu hỏi của riêng tôi và trả lời có vẻ lạ. Vì vậy, tôi sẽ chỉ để lại điều này ở đây.

Tôi đã gặp lỗi tương tự như bạn gặp phải. Tuy nhiên, tôi quản lý để giải quyết nó bằng cách thay đổi của tôi

export default {Class} 

để

export default Class 

Tôi không biết tại sao tôi quấn các Class trong một đối tượng nhưng tôi nhớ mình đã nhìn thấy nó ở đâu đó vì vậy tôi chỉ mới bắt đầu sử dụng nó.

Vì vậy, thay vì trả về mặc định một Lớp, nó trả về một đối tượng như thế này {Class: Class}. Điều này là hoàn toàn hợp lệ nhưng nó sẽ phá vỡ webpack + babel.

EDIT: Tôi đã biết lý do tại sao điều này có thể phá vỡ babel + webpack. Các export default có nghĩa là chỉ có 1 xuất khẩu. Một đối tượng javascript có thể chứa nhiều thuộc tính. Có nghĩa là nó có thể có nhiều hơn 1 xuất khẩu. (Xem: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).

Để sử dụng nhiều lần xuất: export {definition1, definition2}.

Trường hợp sử dụng: Tôi đã sử dụng trường hợp này trong trường hợp tôi đã tạo thư viện đã xuất các loại trình chỉnh sửa khác nhau (trong khi mã cơ bản giống nhau, giao diện của trình chỉnh sửa thay đổi tùy thuộc vào việc xuất bạn sử dụng).

+0

Cảm ơn bạn đã chia sẻ trải nghiệm của mình về lỗi này :) –

0

Mặc dù đây không phải là nguyên nhân của vấn đề cụ thể của bạn, tôi đã gặp phải sự cố tương tự khi cố gắng tách con lươn ra khỏi ứng dụng nút hiện có đang sử dụng cú pháp importexport của ES6. khác đấu tranh với điều này trong tương lai.

Babel sẽ giải quyết mọi phụ thuộc vòng tròn giữa một mô-đun và một mô-đun khác, vì vậy bạn có thể sử dụng số importexport của ES6 với sự bỏ qua liều lĩnh. Tuy nhiên, nếu bạn cần loại bỏ babel và sử dụng nút gốc, bạn cần phải thay thế bất kỳ importexports nào bằng require. Điều này có thể giới thiệu lại các vấn đề tham chiếu vòng tròn tiềm ẩn mà babel đã quan tâm trong nền. Nếu bạn thấy mình trong tình huống này, hãy tìm một khu vực trong mã của bạn trông như thế này:

file A:

const B = require('B'); 

class A { 
    constructor() { 
    this.b = new B(); 
    } 
} 
module.exports = A; 

File B:

const A = require('A'); // this line causes the error 

class B { 
    constructor() { 
    this.a = new A(); 
    } 
} 
module.exports = B; 

Có nhiều cách khác nhau để giải quyết vấn đề này tùy thuộc vào cách bạn cấu trúc mã của mình. Cách dễ nhất có thể là để chuyển B tham chiếu đến A thay vì tạo một phiên bản mới của lớp A. Bạn cũng có thể tự động giải quyết tham chiếu khi tải A. Có rất nhiều lựa chọn thay thế khác, nhưng đây là một nơi tốt để bắt đầu.

Các vấn đề liên quan