Open vakrilov opened 5 years ago
Actually this issue actually can cause a lot more issues and I think we need to figure out some sort of easy solution...
Because vendor is evaluated and ran before the bundle; their is no easy way to polyfill any missing things that a non-nativescript npm module might be missing. For example I just ran into two of them today...
Normally in the past you could easily do a
require('nativescript-websocket');
at the app.?s
/main.?s
files. And WebSocket
would be setup for all other files after it...
However, in this fairly simple angular project; other files the the router calling the library that requires websockets causes webpack to prioritize other npm modules as a higher priority, than the nativescript-websocket. So then the order gets screwed up. The only way I was able to work around this issue was to EVERY single place one of the files that needed a polyfill was required, was to require a new file called "polyfills.js" before it.
It seems there IS an easy solution. webpack.config.js:
const entries = { bundle: [`${appFullPath}/polyfills.ts`, entryPath] };
app/polyfills.ts:
(<any> global).window = {};
Result:
JS: isNotBrowser: false
Also works:
main.ts:
import "./polyfills";
// rest of the code
The issue is that require
s will run before any code in the file, so moving your polyfills to a separate file and then importing them will work.
Actual generated file. Note that all requires will run first, and since ./polyfills.ts
is the first, it'll polyfill before everything else:
/***/ "./app.ts":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony import */ var _polyfills__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./polyfills.ts");
/* harmony import */ var _polyfills__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_polyfills__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _datorama_akita__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("../node_modules/@datorama/akita/fesm5/datorama-akita.js");
/* harmony import */ var tns_core_modules_application__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("../node_modules/tns-core-modules/application/application.js");
/* harmony import */ var tns_core_modules_application__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tns_core_modules_application__WEBPACK_IMPORTED_MODULE_2__);
let applicationCheckPlatform = __webpack_require__("../node_modules/tns-core-modules/application/application.js");
if (applicationCheckPlatform.android && !global["__snapshot"]) {
__webpack_require__("../node_modules/tns-core-modules/ui/frame/frame.js");
__webpack_require__("../node_modules/tns-core-modules/ui/frame/activity.js");
}
__webpack_require__("../node_modules/nativescript-dev-webpack/load-application-css-regular.js")();
if (false) {}
const context = __webpack_require__("./ sync recursive (?<!\\bApp_Resources\\b.*)\\.(xml|css|js|(?<!\\.d\\.)ts|(?<!\\b_[\\w-]*\\.)scss)$");
global.registerWebpackModules(context);
if (false) {}
__webpack_require__("../node_modules/tns-core-modules/bundle-entry-points.js");
/*
In NativeScript, the app.ts file is the entry point to your application.
You can use this file to perform app-level initialization, but the primary
purpose of the file is to pass control to the app’s first module.
*/
global.window = {};
console.log("isNotBrowser: " + _datorama_akita__WEBPACK_IMPORTED_MODULE_1__["isNotBrowser"]);
tns_core_modules_application__WEBPACK_IMPORTED_MODULE_2__["run"]({ moduleName: "app-root" });
As for nativescript-websockets
, I used a plugin replacement from ws
to nativescript-websockets
and it worked well enough for my remote devtools ngrx implementation, so this solution may also apply: https://github.com/edusperoni/ngrx-ns/blob/master/webpack.config.js#L332
Edit:
@NathanaelA sorry, I didn't read your last paragraph properly. When I imported it in main.ts I didn't need to polyfill anywhere else and was able to import and check isNotBrowser
in other files.
Edit 2: Also worked with require("nativescript-websockets")
Not sure this classifies as a bug or whether it can be solved. Logging it, there might be other similar cases with libraries that depend on the global scope to do environment checks.
Environment Provide version numbers for the following components (information can be retrieved by running
tns info
in your project folder or by inspecting thepackage.json
of the project):Describe the bug I have different behavior when running with and without webpack
To Reproduce Create project:
Go to
app.ts
adn paste the following code beforeapplication.run
:Run with and without bundle and get different results:
Expected behavior
isNotBrowser
to have the same value in both runs.Explanation Here is how
isNotBrowser
is implemented in Akita (here):When running WITHOUT bundle the
window
is attached in the global scope and then the library is evaluated after ->isNotBrowser: false
as window is defined at the time of evaluation (as you would expect).When running WITH bundle, the akita code-base is put inside the
vendor.js
and executed before,bundle.js
(where the fakewindow
is deified). Theimport { isNotBrowser } from "@datorama/akita";
is replaced with webpack-require which returns the already evaluated value ofisNotBrowser
. Thus the difference in behavior.