使用 webpack 定义全局变量
Define global variable with webpack
是否可以用 webpack 定义一个全局变量来产生这样的结果:
var myvar = {};
我看到的所有例子都是使用外部文件require("imports?$=jquery!./file.js")
您可以使用定义window.myvar = {}
。
想用的时候可以用like window.myvar = 1
我正要问同样的问题。在进一步搜索并解密了 webpack 文档的一部分之后,我认为你想要的是 webpack.config.js
文件中的 output.library
和 output.libraryTarget
。
例如:
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'
...
}
现在,如果您 link 在 html 脚本标签中生成的 www/js/index.js
文件,您可以从其他脚本中的任何位置访问 myLibrary.foo
。
有几种处理全局变量的方法:
1。将变量放入模块中。
Webpack 仅对模块求值一次,因此您的实例保持全局并在模块之间进行更改。 因此,如果您创建类似 globals.js
的内容并导出一个你所有全局变量的对象然后你可以 import './globals'
和 read/write 这些全局变量。您可以导入到一个模块中,从函数中更改对象,然后导入到另一个模块中,然后在函数中读取这些更改。还要记住事情发生的顺序。 Webpack 将首先获取所有导入并从您的 entry.js
开始按顺序加载它们。然后它会执行entry.js
。所以你 read/write 到全局变量的位置很重要。它是来自模块的根范围还是在稍后调用的函数中?
config.js
export default {
FOO: 'bar'
}
somefile.js
import CONFIG from './config.js'
console.log(`FOO: ${CONFIG.FOO}`)
注意:如果你希望实例每次都是new
,那么使用一个ES6 class。传统上,在 JS 中,您会将 类 大写(相对于对象的小写),如
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()
2。使用 Webpack 的 ProvidePlugin.
以下是使用 Webpack 的 ProvidePlugin 实现的方法(它使模块在每个模块中都可以作为变量使用,并且仅在您实际使用它的那些模块中可用)。当您不想一次又一次地输入 import Bar from 'foo'
时,这很有用。或者,您可以在此处引入 jQuery 或 lodash 之类的包作为全局包(尽管您可能会看看 Webpack 的 Externals)。
步骤 1. 创建任意模块。例如,一组全局实用程序会很方便:
utils.js
export function sayHello () {
console.log('hello')
}
第 2 步。为模块添加别名并添加到 ProvidePlugin:
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'
})
]
}
现在只要在任何 js 文件中调用 utils.sayHello()
就可以了。如果您将开发服务器与 Webpack 一起使用,请确保重启您的开发服务器。
注意:不要忘记告诉你的 linter 关于全局的,所以它不会抱怨。比如看我的.
3。使用 Webpack 的 DefinePlugin.
如果您只想将 const 与全局变量的字符串值一起使用,那么您可以将此插件添加到您的 Webpack 插件列表中:
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
BROWSER_SUPPORTS_HTML5: true,
TWO: "1+1",
"typeof window": JSON.stringify("object")
})
像这样使用它:
console.log("Running App version " + VERSION);
if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");
4。使用全局 window 对象(或 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/
你会看到这个常用于 polyfill,例如:window.Promise = Bluebird
5。使用像 dotenv.
这样的包
(对于服务器端项目)dotenv 包将获取一个本地配置文件(如果有的话,你可以将其添加到你的 .gitignore keys/credentials)并将你的配置变量添加到 Node 的 process.env 对象。
// As early as possible in your application, require and configure dotenv.
require('dotenv').config()
在项目的根目录中创建一个 .env
文件。以 NAME=VALUE
的形式在新行上添加特定于环境的变量。例如:
DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3
就是这样。
process.env
现在具有您在 .env
文件中定义的键和值。
var db = require('db')
db.connect({
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS
})
备注
关于 Webpack 的 Externals,如果你想排除某些模块不包含在你的构建包中,请使用它。 Webpack 将使该模块全局可用,但不会将其放入您的包中。这对于像 jQuery 这样的大型库来说很方便(因为 tree shaking 外部包 在 Webpack 中不起作用),你已经在单独的脚本标签中将它们加载到你的页面上(也许来自 CDN)。
使用DefinePlugin.
The DefinePlugin allows you to create global constants which can be
configured at compile time.
new webpack.DefinePlugin(definitions)
示例:
plugins: [
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true)
})
//...
]
用法:
console.log(`Environment is in production: ${PRODUCTION}`);
我通过将全局变量设置为最相关的 类 上的静态属性解决了这个问题。在 ES5 中它看起来像这样:
var Foo = function(){...};
Foo.globalVar = {};
DefinePlugin 实际上并没有定义任何东西。它的作用是替换捆绑包代码中存在的变量。如果您的代码中不存在该变量,它将什么都不做。所以它不会创建全局变量。
为了创建一个全局变量,在你的代码中这样写:
window.MyGlobal = MY_GLOBAL;
并使用 DefinePlugin 将 MY_GLOBAL
替换为一些代码:
new webpack.DefinePlugin({
'MY_GLOBAL': `'foo'`,
// or
'MY_GLOBAL': `Math.random()`,
}),
那么你的输出JS会是这样的:
window.MyGlobal = 'foo';
// or
window.MyGlobal = Math.random();
但是 MY_GLOBAL
在运行时将永远不会实际存在,因为它从未被定义。所以这就是为什么 DefinePlugin 有一个误导性的名字。
是否可以用 webpack 定义一个全局变量来产生这样的结果:
var myvar = {};
我看到的所有例子都是使用外部文件require("imports?$=jquery!./file.js")
您可以使用定义window.myvar = {}
。
想用的时候可以用like window.myvar = 1
我正要问同样的问题。在进一步搜索并解密了 webpack 文档的一部分之后,我认为你想要的是 webpack.config.js
文件中的 output.library
和 output.libraryTarget
。
例如:
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'
...
}
现在,如果您 link 在 html 脚本标签中生成的 www/js/index.js
文件,您可以从其他脚本中的任何位置访问 myLibrary.foo
。
有几种处理全局变量的方法:
1。将变量放入模块中。
Webpack 仅对模块求值一次,因此您的实例保持全局并在模块之间进行更改。 因此,如果您创建类似 globals.js
的内容并导出一个你所有全局变量的对象然后你可以 import './globals'
和 read/write 这些全局变量。您可以导入到一个模块中,从函数中更改对象,然后导入到另一个模块中,然后在函数中读取这些更改。还要记住事情发生的顺序。 Webpack 将首先获取所有导入并从您的 entry.js
开始按顺序加载它们。然后它会执行entry.js
。所以你 read/write 到全局变量的位置很重要。它是来自模块的根范围还是在稍后调用的函数中?
config.js
export default {
FOO: 'bar'
}
somefile.js
import CONFIG from './config.js'
console.log(`FOO: ${CONFIG.FOO}`)
注意:如果你希望实例每次都是new
,那么使用一个ES6 class。传统上,在 JS 中,您会将 类 大写(相对于对象的小写),如
import FooBar from './foo-bar' // <-- Usage: myFooBar = new FooBar()
2。使用 Webpack 的 ProvidePlugin.
以下是使用 Webpack 的 ProvidePlugin 实现的方法(它使模块在每个模块中都可以作为变量使用,并且仅在您实际使用它的那些模块中可用)。当您不想一次又一次地输入 import Bar from 'foo'
时,这很有用。或者,您可以在此处引入 jQuery 或 lodash 之类的包作为全局包(尽管您可能会看看 Webpack 的 Externals)。
步骤 1. 创建任意模块。例如,一组全局实用程序会很方便:
utils.js
export function sayHello () {
console.log('hello')
}
第 2 步。为模块添加别名并添加到 ProvidePlugin:
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'
})
]
}
现在只要在任何 js 文件中调用 utils.sayHello()
就可以了。如果您将开发服务器与 Webpack 一起使用,请确保重启您的开发服务器。
注意:不要忘记告诉你的 linter 关于全局的,所以它不会抱怨。比如看我的
3。使用 Webpack 的 DefinePlugin.
如果您只想将 const 与全局变量的字符串值一起使用,那么您可以将此插件添加到您的 Webpack 插件列表中:
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
BROWSER_SUPPORTS_HTML5: true,
TWO: "1+1",
"typeof window": JSON.stringify("object")
})
像这样使用它:
console.log("Running App version " + VERSION);
if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");
4。使用全局 window 对象(或 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/
你会看到这个常用于 polyfill,例如:window.Promise = Bluebird
5。使用像 dotenv.
这样的包(对于服务器端项目)dotenv 包将获取一个本地配置文件(如果有的话,你可以将其添加到你的 .gitignore keys/credentials)并将你的配置变量添加到 Node 的 process.env 对象。
// As early as possible in your application, require and configure dotenv.
require('dotenv').config()
在项目的根目录中创建一个 .env
文件。以 NAME=VALUE
的形式在新行上添加特定于环境的变量。例如:
DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3
就是这样。
process.env
现在具有您在 .env
文件中定义的键和值。
var db = require('db')
db.connect({
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS
})
备注
关于 Webpack 的 Externals,如果你想排除某些模块不包含在你的构建包中,请使用它。 Webpack 将使该模块全局可用,但不会将其放入您的包中。这对于像 jQuery 这样的大型库来说很方便(因为 tree shaking 外部包 在 Webpack 中不起作用),你已经在单独的脚本标签中将它们加载到你的页面上(也许来自 CDN)。
使用DefinePlugin.
The DefinePlugin allows you to create global constants which can be configured at compile time.
new webpack.DefinePlugin(definitions)
示例:
plugins: [
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true)
})
//...
]
用法:
console.log(`Environment is in production: ${PRODUCTION}`);
我通过将全局变量设置为最相关的 类 上的静态属性解决了这个问题。在 ES5 中它看起来像这样:
var Foo = function(){...};
Foo.globalVar = {};
DefinePlugin 实际上并没有定义任何东西。它的作用是替换捆绑包代码中存在的变量。如果您的代码中不存在该变量,它将什么都不做。所以它不会创建全局变量。
为了创建一个全局变量,在你的代码中这样写:
window.MyGlobal = MY_GLOBAL;
并使用 DefinePlugin 将 MY_GLOBAL
替换为一些代码:
new webpack.DefinePlugin({
'MY_GLOBAL': `'foo'`,
// or
'MY_GLOBAL': `Math.random()`,
}),
那么你的输出JS会是这样的:
window.MyGlobal = 'foo';
// or
window.MyGlobal = Math.random();
但是 MY_GLOBAL
在运行时将永远不会实际存在,因为它从未被定义。所以这就是为什么 DefinePlugin 有一个误导性的名字。