bundling CesiumJS using RollupJS - cesiumjs

I am trying to bundle CesiumJS with Rollup. I thought I could just do an import like this:
import Cesium from 'cesium/Build/Cesium/Cesium.js'
with the following rollup.config.js file. I am getting a bundle.js but when I run it I get lots errors:
Uncaught TypeError: Cannot read property 'document' of undefined
at bundle.js:formatted:102314
function() {
!function(e) {
var t = this || eval("this")
, r = t.document // it is complaining on this line
, i = t.navigator
, n = t.jQuery
, o = t.JSON;
rollup.config.js
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import uglify from 'rollup-plugin-uglify'
import { minify } from 'uglify-es'
export default {
input: 'scripts/Main.js',
output: {
file: 'dist/bundle.js',
format: 'es',
},
"options": {
sourceMap: 'inline',
output: {
format: 'es'
}
},
plugins: [
resolve({
jsnext: true,
main: true,
browser: true,
}),
commonjs(),
uglify({}, minify)
]
}

ES modules are always in strict mode — by extension, when something is imported into Rollup and converted to an ES module, it also runs in strict mode.
In strict mode, the value of this inside a function is undefined, unless it's a) called as a method, or b) explicitly set with call or apply.
This is expected behaviour with Rollup, and it isn't technically a bug with Cesium, but I would suggest raising an issue with them and seeing if they can use a more modern way of accessing the global variable. There's really no reason to be relying on non-strict behaviour in 2017!
As a last resort you could string-replace this || eval("this") (or this||(0,eval)("this"), as it is in the minified version) with window.
If there are lots of other errors after making that change, it may be impossible to include Cesium in your bundle, and you would need to keep it as an external module.

Related

Reading from JSON

I'm trying to read my i18n-strings from a JSON file following this guide.
I have en-US.json:
{
"world": "the world!"
}
And for setting up my Vue app I use:
import { createI18n } from 'vue-i18n'
import enUS from '../src/i18n/en-US.json'
// Type-define 'en-US' as the master schema for the resource
type MessageSchema = typeof enUS
const i18n = createI18n<[MessageSchema], 'en-US'>({
locale: 'en-US',
messages: {
'en-US': enUS
}
})
This works. But as soon as I add one non-ASCII char (e.g. "world": "the w#rld!"), I get the following error message:
[plugin:vite-plugin-vue-i18n] Cannot read properties of undefined (reading 'message')
/home/bernhard/wd/quasar2-project/src/i18n/en-US.json
Strangely, this works when I do the following straight in my .ts file:
const enUS = {
"world": "the w#rld!"
}
so maybe something wrong with the way the JSON is processed?
The answer has two layers.
As #jonrsharpe pointed out, there is a set of special characters: { } # $ | - i.e. for inserting variables. A # should i.e. be replaced by {'#'}.
A bug in how vite processes external json as described on this bug on Github. By default, quasar is using "#intlify/vite-plugin-vue-i18n": "^3.3.1". Changing that to "#intlify/vite-plugin-vue-i18n": "^7.0.0" solved the issue.

NextJs Webpack asset/source returns JSON as a string

Looking for some help to understand what is going on here.
The Problem
We are using a translation service that requires creating JSON resource files of copy, and within these resource files, we need to add some specific keys that the service understands so it knows what should and should not be translated.
To do this as simple as possible I want to import JSON files into my code without them being tree shaken and minified. I just need the plain JSON file included in my bundle as a JSON object.
The Solution - or so I thought
The developers at the translation service have instructed me to create a webpack rule with a type of assets/source to prevent tree shaking and modification.
This almost works but the strange thing is that the JSON gets added to the bundle as a string like so
module.exports = "{\n \"sl_translate\": \"sl_all\",\n \"title\": \"Page Title\",\n \"subtitle\": \"Page Subtitle\"\n}\n";
This of course means that when I try and reference the JSON values in my JSX it fails.
Test Repo
https://github.com/lukehillonline/nextjs-json-demo
NextJs 12
Webpack 5
SSR
Steps To Reproduce
Download the test repo and install packages
Run yarn build and wait for it to complete
Open /.next/server/pages/index.js to see the SSR page
On line 62 you'll find the JSON object as a string
Open .next/static/chunks/pages/index-{HASH}.js to see the Client Side page
If you format the code you'll find the JSON object as a string on line 39
Help!
If anyone can help me understand what is going wrong or how I can improve the webpack rule to return a JSON object rather than a string that would be a massive help.
Cheers!
The Code
next.config.js
module.exports = {
trailingSlash: true,
productionBrowserSourceMaps: true,
webpack: function (config) {
config.module.rules.push({
test: /\.content.json$/,
type: "asset/source",
});
return config;
},
};
Title.content.json
{
"sl_translate": "sl_all",
"title": "Page Title",
"subtitle": "Page Subtitle"
}
Title.jsx
import content from "./Title.content.json";
export function Title() {
return <h1>{content.title}</h1>;
}
pages/index.js
import { Title } from "../components/Title/Title";
function Home({ dummytext }) {
return (
<div>
<Title />
<p>{dummytext}</p>
</div>
);
}
export const getServerSideProps = async () => {
const dummytext = "So we can activate SSR";
return {
props: {
dummytext,
},
};
};
export default Home;

Error: 'Map' is not exported from 'react-leaflet' (imported as 'LeafletMap')

Here is my code:
import { Map as LeafletMap, TileLayer } from 'react-leaflet';
function Map() {
return (
<div className="map">
<LeafletMap>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'/>
</LeafletMap>
</div>
But I got an error saying Attempted import error: 'Map' is not exported from 'react-leaflet' (imported as 'LeafletMap'). I've tried changing the 'import { Map' to 'import { MapContainer' but still won't work. Instead I got another error saying:
./node_modules/#react-leaflet/core/esm/path.js 10:41
Module parse failed: Unexpected token (10:41)
File was processed with these loaders:
* ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| useEffect(function updatePathOptions() {
| if (props.pathOptions !== optionsRef.current) {
> const options = props.pathOptions ?? {};
| element.instance.setStyle(options);
| optionsRef.current = options;
I also tried changing the react-leaflet version from ^3.2.1 to ^2.7.0 and leaflet from ^1.7.1 to ^1.6.0. But still no luck. Any solutions?
You'll have to explicitly transpile react-leaflet because the maintainer is not understanding they should change their transpilation target to a lower version in order to more fully support the nullish coalescing operator: https://github.com/PaulLeCam/react-leaflet/issues/877#issuecomment-841871904
You can try adding this to your babel config
{
"plugins": ["#babel/plugin-proposal-nullish-coalescing-operator"]
}
And then make sure you transpile node_modules/react-leaflet during your build. If you are already using #babel/preset-env then you only need to make sure you're transpiling react-leaflet during the build. If you're using webpack you can do something like
module: {
rules: [
{
test: /\.jsx?$/,
exclude: filename => {
return /node_modules/.test(filename) && !/react-leaflet/.test(filename)
},
use: ['babel-loader']
}
]
}

Rest-spread not being transpiled when targeting edge with NextJS

I am trying to transpile my ES6 code via Babel, I am using the next/babel preset along with preset-env and I'm using the browsers: defaults target.
The NextJS preset comes with #babel/plugin-proposal-object-rest-spread in its plugins array, I'm wondering why I am getting an error when testing on edge that says Expected identifier, string or number, and when looking in the compiled JS for the error, I see it happens when {...t} occurs.
Here is my babel.config.js:
module.exports = {
presets: [
[
'next/babel',
{
'#babel/preset-env': {
targets: {
browsers: 'defaults'
},
useBuiltIns: 'usage'
}
}
]
],
plugins: [
'#babel/plugin-proposal-optional-chaining',
'#babel/plugin-proposal-nullish-coalescing-operator',
['styled-components', { ssr: true, displayName: true, preprocess: false }],
[
'module-resolver',
{
root: ['.', './src']
}
]
],
env: {
development: {
compact: false
}
}
};
Any help on this would be greatly appreciated!
In the end my problem was related to a package that was not being transpiled by babel. My solution was to use NextJS' next-transpile-modules plugin to get babel to transpile the package code into something that would work on the browsers I need.
Here's an example of my NextJS webpack config with the package I need transpiled specified:
const withTM = require('next-transpile-modules');
module.exports = withTM({
transpileModules: ['swipe-listener']
});
SCRIPT1028: Expected identifier, string or number error can occur in 2 situations.
(1) This error get trigger if you are using trailing comma after your last property in a JavaScript object.
Example:
var message = {
title: 'Login Unsuccessful',
};
(2) This error get trigger if you are using a JavaScript reserved word as a property name.
Example:
var message = {
class: 'error'
};
solution is to pass the class property value as a string. You will need to use bracket notation, however, to call the property in your script.
Reference:
ERROR : SCRIPT1028: Expected identifier, string or number

"this" in underscore is undefined after compiling with browserify and debowerify

So first.. I have next gulp task:
gulp.task('js', function() {
browserify('./src/js/main.js')
.bundle()
.on('error', onError)
.pipe( source('main.js') )
.pipe( gulp.dest(path.build.js) );
});
and package.json:
{
"browserify": {
"transform": [
["babelify", { "presets": ["es2015"] }],
"debowerify"
]
},
}
I am importing Backbone in main.js (or only underscore... it doesn't matter)
import Backbone from 'backbone';
And in console I am getting error
Uncaught TypeError: Cannot read property '_' of undefined
I checked code and found that in underscore sources at start of library root is undefined
// Establish the root object, `window` in the browser, or `exports` on the server.
var root = this;
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
I think the problem is that debowerify or babelfy is wrapping code in some function. But also if I use node modules without debowerify all works fine. But I want to use bower.
So how to fix this problem?
To any future visitors to this question,
this is similar to Underscore gives error when bundling with Webpack
The gist of the issue is that babel is probably running the underscore.js code, since underscore.js uses this, and in es6 this is undefined when outside of a function, naturally this._ fails.
In code I've fixed the issue by ensuring that babel does not run on node_modules.
In my case the same error arose when using just browserify with underscore. I've workarounded issue by switching from underscore to lodash. They are in general (surely not fully) compatible, but at the worst I'd rather copy some missing function from underscore sources than live with its deisolated load approach.