Xác định biến toàn cục với webpack


138

Có thể định nghĩa một biến toàn cục với webpack để tạo ra kết quả như thế này không:

var myvar = {};

Tất cả các ví dụ tôi thấy là sử dụng tệp bên ngoài require("imports?$=jquery!./file.js")

Câu trả lời:


272

Có một số cách để tiếp cận toàn cầu:

1) Đặt các biến của bạn trong một mô-đun.

Webpack chỉ đánh giá các mô-đun một lần, vì vậy cá thể của bạn vẫn toàn cầu và mang các thay đổi thông qua từ mô-đun này sang mô-đun khác. Vì vậy, nếu bạn tạo một cái gì đó giống như globals.jsvà xuất một đối tượng của tất cả các quả cầu của bạn thì bạn có thể import './globals'và đọc / ghi vào các quả cầu này. Bạn có thể nhập vào một mô-đun, thay đổi đối tượng từ một chức năng và nhập vào một mô-đun khác và đọc những thay đổi đó trong một chức năng. Cũng nhớ thứ tự xảy ra. Webpack trước tiên sẽ lấy tất cả các nhập khẩu và tải chúng lên để bắt đầu trong của bạn entry.js. Sau đó, nó sẽ thực thi entry.js. Vì vậy, nơi bạn đọc / ghi vào toàn cầu là rất quan trọng. Có phải từ phạm vi gốc của một mô-đun hoặc trong một chức năng được gọi là sau này?

Lưu ý : Nếu bạn muốn cá thể là newmỗi lần, thì hãy sử dụng lớp ES6 . Theo truyền thống trong JS, bạn sẽ viết hoa các lớp (trái ngược với chữ thường cho các đối tượng) như
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()

2) ProvPlugin của Webpack

Dưới đây là cách bạn có thể thực hiện bằng cách sử dụng ProvPlugin của Webpack (làm cho một mô-đun có sẵn dưới dạng một biến trong mọi mô-đun và chỉ những mô-đun nơi bạn thực sự sử dụng nó). Điều này hữu ích khi bạn không muốn tiếp tục gõ import Bar from 'foo'lại nhiều lần. Hoặc bạn có thể mang một gói như jQuery hoặc lodash dưới dạng toàn cầu tại đây (mặc dù bạn có thể xem Externals của Webpack ).

Bước 1) Tạo bất kỳ mô-đun. Ví dụ: một bộ tiện ích toàn cầu sẽ có ích:

utils.js

export function sayHello () {
  console.log('hello')
}

Bước 2) Bí danh mô-đun và thêm vào ProvPlugin:

webpack.config.js

var webpack = require("webpack");
var path = require("path");

// ...

module.exports = {

  // ...

  resolve: {
    extensions: ['', '.js'],
    alias: {
      'utils': path.resolve(__dirname, './utils')  // <-- When you build or restart dev-server, you'll get an error if the path to your utils.js file is incorrect.
    }
  },

  plugins: [

    // ...

    new webpack.ProvidePlugin({
      'utils': 'utils'
    })
  ]  

}

Bây giờ chỉ cần gọi utils.sayHello()trong bất kỳ tập tin js và nó sẽ hoạt động. Đảm bảo bạn khởi động lại máy chủ dev của mình nếu bạn đang sử dụng nó với Webpack.

Lưu ý: Đừng quên nói với người nói dối của bạn về toàn cầu, vì vậy nó sẽ không phàn nàn. Ví dụ, xem câu trả lời của tôi cho ESLint ở đây .

3) Sử dụng DefinePlugin của Webpack

Nếu bạn chỉ muốn sử dụng const với các giá trị chuỗi cho toàn cầu của mình, thì bạn có thể thêm plugin này vào danh sách các plugin Webpack của mình:

new webpack.DefinePlugin({
  PRODUCTION: JSON.stringify(true),
  VERSION: JSON.stringify("5fa3b9"),
  BROWSER_SUPPORTS_HTML5: true,
  TWO: "1+1",
  "typeof window": JSON.stringify("object")
})

Sử dụng nó như:

console.log("Running App version " + VERSION);
if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");

4) Sử dụng đối tượng cửa sổ toàn cầu (hoặc toàn cầu của Node)

window.foo = 'bar'  // For SPA's, browser environment.
global.foo = 'bar'  // Webpack will automatically convert this to window if your project is targeted for web (default), read more here: https://webpack.js.org/configuration/node/

Bạn sẽ thấy điều này thường được sử dụng cho polyfill, ví dụ: window.Promise = Bluebird

5) Sử dụng gói như dotenv

(Đối với các dự án phía máy chủ) Gói dotenv sẽ lấy tệp cấu hình cục bộ (mà bạn có thể thêm vào .gitignore nếu có bất kỳ khóa / thông tin xác thực nào) và thêm các biến cấu hình của bạn vào đối tượng process.env của Node .

// As early as possible in your application, require and configure dotenv.    
require('dotenv').config()

Tạo một .envtập tin trong thư mục gốc của dự án của bạn. Thêm các biến cụ thể cho môi trường trên các dòng mới ở dạng NAME=VALUE. Ví dụ:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

Đó là nó.

process.envbây giờ có các khóa và giá trị bạn đã xác định trong .envtệp của mình .

var db = require('db')
db.connect({
  host: process.env.DB_HOST,
  username: process.env.DB_USER,
  password: process.env.DB_PASS
})

Ghi chú:

Về Externals của Webpack , hãy sử dụng nó nếu bạn muốn loại trừ một số mô-đun khỏi gói được xây dựng. Webpack sẽ làm cho mô-đun có sẵn trên toàn cầu nhưng sẽ không đặt nó trong gói của bạn. Điều này rất hữu ích cho các thư viện lớn như jQuery (vì các gói bên ngoài rung cây không hoạt động trong Webpack ) khi bạn đã tải chúng trên trang của mình trong các thẻ script riêng biệt (có lẽ từ CDN).


3
+1. Tôi đang cấu trúc lại một ứng dụng để tận dụng gói web như một công cụ xây dựng và điều này ban đầu không hiệu quả với tôi vì tôi không bao gồm bất kỳ tham chiếu nào đến utilskhông gian tên của riêng mình trong tệp mục tiêu - ban đầu tôi chỉ đặt một điểm dừng trong trình duyệt cửa sổ nguồn và tôi tiếp tục bối rối về lý do tại sao utilskhông được xác định. Cuối cùng tôi phát hiện ra rằng gói web (khá thông minh) chỉ bao gồm một mô-đun nếu không gian tên của nó được tham chiếu ít nhất một lần. Do đó, một khi tôi đã mở đầu một trong các chức năng tiện ích của tệp mục tiêu utils, mô-đun được bao gồm.
nb1987

Yup, chỉ khi bạn sử dụng nó, nó sẽ làm cho nó có sẵn. Tôi đặt nó ở dòng đầu tiên của câu trả lời, nhưng tôi đã điều chỉnh một chút để có thể nó đọc tốt hơn. Cảm ơn +1!
prograhammer

1
Lưu ý rằng ProvPlugin thực sự tải các mô-đun và nếu bạn chỉ cần một biến, nó không hoạt động theo cách đó. Chỉ cần sử dụng externalsthay thế nếu bạn cần tạo một biến toàn cục. Ví dụ: externals: { 'webpackVariables': `{ serverUrl: '${ env.server }', cordovaBuild: '${ env.cordova }', }`, }, Sau đó sử dụng nó nhưconst webpackVariables = require('webpackVariables');
Brian Haak

1
Và bạn có biết làm thế nào tôi có thể sử dụng phương pháp này với TypeScript không? Ở đó, nếu bạn sử dụng một biến không được khai báo, nó sẽ gây ra lỗi ...
knaos

2
@prograhammer Thật ra, tôi đã tìm ra giải pháp. Trong thư mục gốc của ứng dụng của bạn, thường là nơi tsconfig.json của bạn , bạn cần thêm một tệp định nghĩa có tên global.d.ts . Trong đó bạn có thể khai báo các biến toàn cầu, như thế này: declare const isProduction: bool;Để tham khảo, hãy khám phá typescriptlang.org/docs/handbook/declaration-files/templates/...
knaos

45

Tôi đã định đặt câu hỏi tương tự. Sau khi tìm kiếm thêm một chút và giải mã một phần tài liệu của webpack, tôi nghĩ rằng những gì bạn muốn là output.libraryoutput.libraryTargettrong webpack.config.jstệp.

Ví dụ:

js / index.js:

var foo = 3;
var bar = true;

webpack.config.js

module.exports = {
   ...
   entry: './js/index.js',
   output: {
      path: './www/js/',
      filename: 'index.js',
      library: 'myLibrary',
      libraryTarget: 'var'
   ...
}

Bây giờ nếu bạn liên kết www/js/index.jstệp được tạo trong thẻ script html, bạn có thể truy cập myLibrary.footừ bất kỳ đâu trong các tập lệnh khác.


3
Tôi nghĩ rằng điều này là mất tích export { foo }từ index.js?
LondonAppDev

myL Library cung cấp không xác định trong một tập tin khác trong trường hợp của tôi. Bạn có thể vui lòng giúp tôi không
RVCoder

17

Sử dụng DefinePlugin .

DefinePlugin cho phép bạn tạo các hằng số toàn cầu có thể được cấu hình tại thời điểm biên dịch.

new webpack.DefinePlugin(definitions)

Thí dụ:

plugins: [
  new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true)
  })
  //...
]

Sử dụng:

console.log(`Environment is in production: ${PRODUCTION}`);

14

Bạn có thể sử dụng định nghĩa window.myvar = {}. Khi bạn muốn sử dụng nó, bạn có thể sử dụng nhưwindow.myvar = 1


Điều này không hoạt động với EMCAScript 6. Tạo ra lỗi với var window.CKEDITOR_BASEPATH = {};Lỗi là "Mã thông báo bất ngờ" sauwindow.
Routhinator

1
Lấy làm tiếc. Tôi vừa cập nhật câu trả lời của tôi. Bạn nên vartừ khóa. window.CKEDITOR_BASEPATH = {};
Anh Nguyễn

Điều này không may, vấn đề tôi gặp phải là tôi cần phải tải nó vào gói trước CKEditor, tuy nhiên Webpack vẫn khăng khăng đặt nó sau khi tôi đặt nó vào mục nhập / js của mình. : /
Người dẫn đầu

2

Tôi đã giải quyết vấn đề này bằng cách đặt các biến toàn cục làm thuộc tính tĩnh trên các lớp mà chúng có liên quan nhất. Trong ES5, nó trông như thế này:

var Foo = function(){...};
Foo.globalVar = {};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.