I wanted to try out Deno, so I decided to make a simple single-page React app.
But, when I try to pull in ReactDOM from the CDN, I get a console error: react_dom_development_js_2 is undefined.
I think what's going on is it can't resolve the ReactDOM CDN, but I can reach it from my browser? I also tried replacing it with what the browser resolves it to (https://unpkg.com/react-dom#16.13.1/umd/react-dom.development.js), but I still end up with the same error. Maybe I'm using the deno bundle wrong?
index.jsx
import { React } from "https://unpkg.com/react#16/umd/react.development.js";
import { ReactDOM } from "https://unpkg.com/react-dom#16/umd/react-dom.development.js";
ReactDOM.render(<p>Hello</p>, document.findElementById("app"));
index.html
<html>
<head>
<title>Test with Deno</title>
</head>
<body>
<div id="app"></div>
<script src="index.bundle.js"></script>
</body>
</html>
I run deno bundle index.jsx index.bundle.js to create my bundle,
index.bundle.js
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This is a specialised implementation of a System module loader.
// #ts-nocheck
/* eslint-disable */
let System, __instantiateAsync, __instantiate;
(() => {
const r = new Map();
System = {
register(id, d, f) {
r.set(id, { d, f, exp: {} });
},
};
async function dI(mid, src) {
let id = mid.replace(/\.\w+$/i, "");
if (id.includes("./")) {
const [o, ...ia] = id.split("/").reverse(),
[, ...sa] = src.split("/").reverse(),
oa = [o];
let s = 0,
i;
while ((i = ia.shift())) {
if (i === "..") s++;
else if (i === ".") break;
else oa.push(i);
}
if (s < sa.length) oa.push(...sa.slice(s));
id = oa.reverse().join("/");
}
return r.has(id) ? gExpA(id) : import(mid);
}
function gC(id, main) {
return {
id,
import: (m) => dI(m, id),
meta: { url: id, main },
};
}
function gE(exp) {
return (id, v) => {
v = typeof id === "string" ? { [id]: v } : id;
for (const [id, value] of Object.entries(v)) {
Object.defineProperty(exp, id, {
value,
writable: true,
enumerable: true,
});
}
};
}
function rF(main) {
for (const [id, m] of r.entries()) {
const { f, exp } = m;
const { execute: e, setters: s } = f(gE(exp), gC(id, id === main));
delete m.f;
m.e = e;
m.s = s;
}
}
async function gExpA(id) {
if (!r.has(id)) return;
const m = r.get(id);
if (m.s) {
const { d, e, s } = m;
delete m.s;
delete m.e;
for (let i = 0; i < s.length; i++) s[i](await gExpA(d[i]));
const r = e();
if (r) await r;
}
return m.exp;
}
function gExp(id) {
if (!r.has(id)) return;
const m = r.get(id);
if (m.s) {
const { d, e, s } = m;
delete m.s;
delete m.e;
for (let i = 0; i < s.length; i++) s[i](gExp(d[i]));
e();
}
return m.exp;
}
__instantiateAsync = async (m) => {
System = __instantiateAsync = __instantiate = undefined;
rF(m);
return gExpA(m);
};
__instantiate = (m) => {
System = __instantiateAsync = __instantiate = undefined;
rF(m);
return gExp(m);
};
})();
System.register(
"index",
[
"https://unpkg.com/react#16/umd/react.development.js",
"https://unpkg.com/react-dom#16/umd/react-dom.development.js",
],
function (exports_1, context_1) {
"use strict";
var react_development_js_1, react_dom_development_js_1;
var __moduleName = context_1 && context_1.id;
return {
setters: [
function (react_development_js_1_1) {
react_development_js_1 = react_development_js_1_1;
},
function (react_dom_development_js_1_1) {
react_dom_development_js_1 = react_dom_development_js_1_1;
},
],
execute: function () {
react_dom_development_js_1.ReactDOM.render(
react_development_js_1.React.createElement("p", null, "Hello"),
document.findElementById("app"),
);
},
};
},
);
__instantiate("index");
The issue here is due to the typical React and ReactDOM packages being written as commonJS packages.
Deno by default requires all modules to be written using ES Modules (ESM). https://github.com/pikapkg/react is a build of React and ReactDOM that use ESM, so they should be importable in Deno. link with CDN
There is a standard library module in deno that lets you use commonJS modules, though you'll need to be careful with them especially if they require node specific functionality: https://deno.land/std/node#commonjs-module-loading
TypeScript does not allow imports from html or that end in a file extension.
So for now you can ignore them using // #ts-ignore which will allow deno to work.
There is a visual studio code extension for deno but at the time of writing it seems to be a bit unstable.
If and when its working correctly you would be able to config deno to work on a per project basis by defining a settings folder in the root of your project e.g. .vscode/settings.json.
{
"deno.enable": true
}
Related
I want to divide an app in a TypeScript development environment into function files - so that each file contains only one function.
I would like to realise this with TS modules. In the compiled JavaScript file, however, these modules should not get imported at runtime, but compiled as native code.
For example, from this app.ts
type ArbitraryAttribute = any //can refer to any value valid at runtime
declare interface App {
get? (key: string): ArbitraryAttribute | void,
set? (key: string, val: ArbitraryAttribute): void,
helper?: AppHelper,
}
declare interface AppHelper {
deepGetter? (key: string): ArbitraryAttribute | void,
deepSetter? (key: string, val: ArbitraryAttribute): void,
}
import { get } from "./get";
import { set } from "./set";
import { helper } from "./helper/index";
const app:App = {
get,
set,
helper,
}
this app.js is to be generated:
var app = {
get: function (key) {
if (app.helper && app.helper.deepGetter) {
return app.helper.deepGetter(key);
};
},
set: function (key, val) {
if (app.helper && app.helper.deepSetter) {
app.helper.deepSetter(key, val);
};
},
helper: {
deepGetter: function (key) {
// get anything
},
deepSetter: function (key, val) {
// set anything
},
},
};
Neither in the TypeScript configuration nor in webpack have I found a solution for this.
This should be feasible, right? Does anyone know a solution or a library that solves this problem?
As #Dimava mentions, via tsconfig there is the possibility to merge a number of typescript files into a single js file, but the result for my aproach is really messy. The previosly postet js file will look like this:
System.register("get", [], function (exports_1, context_1) {
"use strict";
var get;
var __moduleName = context_1 && context_1.id;
return {
setters: [],
execute: function () {
exports_1("get", get = function (key) {
if (app.helper && app.helper.deepGetter) {
return app.helper.deepGetter(key);
}
;
});
}
};
});
System.register("set", [], function (exports_2, context_2) {
"use strict";
var set;
var __moduleName = context_2 && context_2.id;
return {
setters: [],
execute: function () {
exports_2("set", set = function (key, val) {
if (app.helper && app.helper.deepSetter) {
return app.helper.deepSetter(key, val);
}
});
}
};
});
System.register("helper/deepGetter", [], function (exports_3, context_3) {
"use strict";
var deepGetter;
var __moduleName = context_3 && context_3.id;
return {
setters: [],
execute: function () {
exports_3("deepGetter", deepGetter = function (key) {
// get anything
});
}
};
});
System.register("helper/deepSetter", [], function (exports_4, context_4) {
"use strict";
var deepSetter;
var __moduleName = context_4 && context_4.id;
return {
setters: [],
execute: function () {
exports_4("deepSetter", deepSetter = function (key, val) {
// set anything
});
}
};
});
System.register("helper/index", ["helper/deepGetter", "helper/deepSetter"], function (exports_5, context_5) {
"use strict";
var deepGetter_1, deepSetter_1, helper;
var __moduleName = context_5 && context_5.id;
return {
setters: [
function (deepGetter_1_1) {
deepGetter_1 = deepGetter_1_1;
},
function (deepSetter_1_1) {
deepSetter_1 = deepSetter_1_1;
}
],
execute: function () {
exports_5("helper", helper = {
deepGetter: deepGetter_1.deepGetter,
deepSetter: deepSetter_1.deepSetter,
});
}
};
});
System.register("index", ["get", "set", "helper/index"], function (exports_6, context_6) {
"use strict";
var get_1, set_1, index_1, app;
var __moduleName = context_6 && context_6.id;
return {
setters: [
function (get_1_1) {
get_1 = get_1_1;
},
function (set_1_1) {
set_1 = set_1_1;
},
function (index_1_1) {
index_1 = index_1_1;
}
],
execute: function () {
app = {
get: get_1.get,
set: set_1.set,
helper: index_1.helper,
};
}
};
});
I haven't get it working for "--module es2015 --moduleResolution classic",
only for for "--module system --moduleResolution node".
And the file weighs almost six and a half times as much!
I am integrating Vite SSR to existing vue project. I copied vite configuration from SSR playground project and bumped ionic version to 6 because of dynamic loading issue from stencil.
After upgrading, it isn't compiling, showing this error.
12:03:15 AM [vite] Error when evaluating SSR module /src/components/ImportType.vue:
/data/Work/ssr-vue/node_modules/#ionic/core/components/ion-accordion.js:4
import { proxyCustomElement, HTMLElement, h, Host } from '#stencil/core/internal/client';
^^^^^^
SyntaxError: Cannot use import statement outside a module
Here is my vite.config.js file
const vuePlugin = require('#vitejs/plugin-vue')
const vueJsx = require('#vitejs/plugin-vue-jsx')
const virtualFile = '#virtual-file'
const virtualId = '\0' + virtualFile
const nestedVirtualFile = '#nested-virtual-file'
const nestedVirtualId = '\0' + nestedVirtualFile
/**
* #type {import('vite').UserConfig}
*/
module.exports = {
plugins: [
vuePlugin(),
vueJsx(),
{
name: 'virtual',
resolveId(id) {
if (id === '#foo') {
return id
}
},
load(id) {
if (id === '#foo') {
return `export default { msg: 'hi' }`
}
}
},
{
name: 'virtual-module',
resolveId(id) {
if (id === virtualFile) {
return virtualId
} else if (id === nestedVirtualFile) {
return nestedVirtualId
}
},
load(id) {
if (id === virtualId) {
return `export { msg } from "#nested-virtual-file";`
} else if (id === nestedVirtualId) {
return `export const msg = "[success] from conventional virtual file"`
}
}
}
],
ssr: {
external: ["npm: #ionic/vue"]
},
build: {
minify: false
}
}
Please help me.
Does anyone know how to use the javascript-obfuscator (or similar) in Ember ?
I guess it needs to be called inside ember-cli-build.js but I don't know where and how.
Thank you in advance for any help :)
I don't think there's a really straightforward answer to this. If you're running on embroider, then all your Javascript will be handled by webpack, so you could try using webpack-obfuscator -- in your ember-cli-build.js something like
return require('#embroider/compat').compatBuild(app, Webpack, {
plugins: [
new WebpackObfuscator(/*whatever args*/)
],
rules: [
{
test: /\.js$/,
enforce: 'post',
use: {
loader: WebpackObfuscator.loader,
}
}
]
});
The other options I know of would be to write a broccoli plugin. What you're doing is analogous to what ember-cli-terser does -- post-process Javascript files before they get concatenated together -- so you could use that as reference.
You would need to write a broccoli plugin that actually performs the transformations (the analog is broccoli-terser-sourcemap) and an Ember addon to hook it into ember-cli's build pipeline (the analog is ember-cli-terser).
Broccoli plugin
Looking at broccoli-terser-sourcemap's index.js, which is only 114 lines of code, I would think you could adapt it to something like this:
module.exports = class TerserWriter extends Plugin {
constructor(_inputNodes, options = {}) {
let inputNodes = Array.isArray(_inputNodes) ? _inputNodes : [_inputNodes];
super(inputNodes, {
name: options.name,
annotation: options.annotation,
needsCache: false,
});
this.options = defaults(options, {
obfuscator: {},
});
let exclude = this.options.exclude;
if (Array.isArray(exclude)) {
this.excludes = new MatcherCollection(exclude);
} else {
this.excludes = MatchNothing;
}
}
async build() {
let pendingWork = [];
this.inputPaths.forEach(inputPath => {
walkSync(inputPath).forEach(relativePath => {
if (relativePath.slice(-1) === '/') {
return;
}
let inFile = path.join(inputPath, relativePath);
let outFile = path.join(this.outputPath, relativePath);
fs.mkdirSync(path.dirname(outFile), { recursive: true });
if (this._isJSExt(relativePath) && !this.excludes.match(relativePath)) {
pendingWork.push(() => this.processFile(inFile, outFile, relativePath, this.outputPath));
} else {
symlinkOrCopy.sync(inFile, outFile);
}
});
});
for (let fn of pendingWork) {
await fn();
}
}
_isJSExt(relativePath) {
return relativePath.slice(-3) === '.js' || relativePath.slice(-4) === '.mjs';
}
async processFile(inFile, outFile, relativePath, outDir) {
let input = await readFile(inFile).toString();
let result = obfuscate(input, this.options.obfuscator);
await writeFile(outFile, result.getObfuscatedCode());
}
};
You could also do the worker pooling this that broccoli-terser-sourcemaps does, and if you care about source maps you'd need to handle them as well, but broccoli-terser-sourcemaps does just that, so you could use it as reference.
ember-cli addon
ember-cli-terser has even less code -- looking at its index.js, you could adapt it to something like
'use strict';
module.exports = {
name: require('./package').name,
included(app) {
this._super.included.apply(this, arguments);
let defaultOptions = {
enabled: app.env === 'production',
obfuscator: {
// default `javascript-obfuscator` options
},
};
let addonOptions = app.options['ember-cli-obfuscator'];
this._obfuscatorOptions = Object.assign({}, defaultOptions, addonOptions);
},
postprocessTree(type, tree) {
if (this._obfuscatorOptions.enabled === true && type === 'all') {
// Import the plugin code above
const Obfuscator = require('./broccoli-obfuscator');
return new Obfuscator(tree, this._obfuscatorOptions);
} else {
return tree;
}
}
};
Then you'd have to install the above addon in your app (it could be an in-repo addon), and it should do its thing!
This would definitely take some doing, but what you're doing is so similar to what ember-cli-terser is doing, just using the obfuscator API instead of the terser API, that you have a really good starting point.
BUT, if embroider is an option for you, I'd definitely try that route first because it might just be a matter of configuration, rather than writing a bunch of code.
I am trying to get object from api.json but it throws error , based on typescript i have added declare module "*.json" into the project , Any idea how can i achieve this task ?
api.json
{
"Refills": {
"getPatientInfo": "Refills/patientInfo/GetPatientInfo"
}
}
index.ts
import {ModuleExecutor} from "./common/ModuleExecutor";
import {Identity} from "./common/Enums";
export class Index {
private executor: ModuleExecutor = null;
// Any string prepended with # is handled by grunt before building the project
// grunt dynamically reads the config/api.json and loads only the apis that are listed there
// api.json consists of the API name and the folder path for grunt
private _apisConfig: string = '#api'
constructor(identity: string) {
this.executor = new ModuleExecutor(Identity[identity]);
const apiConfig = JSON.parse(this._apisConfig);
console.log('API', apiConfig);
for (const module in apiConfig) {
if (apiConfig.hasOwnProperty(module)) {
this[module] = {};
for (const api in apiConfig[module]) {
if (apiConfig[module].hasOwnProperty(api)) {
this[module][api] = this.executor.execute(apiConfig[module][api]);
}
}
}
}
}
}
Error
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
Compiled index.js file
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ModuleExecutor_1 = require("./common/ModuleExecutor");
const Enums_1 = require("./common/Enums");
class Index {
constructor(identity) {
this.executor = null;
this._apisConfig = '';
this.executor = new ModuleExecutor_1.ModuleExecutor(Enums_1.Identity[identity]);
const apiConfig = JSON.parse(this._apisConfig);
console.log('API', apiConfig);
for (const module in apiConfig) {
if (apiConfig.hasOwnProperty(module)) {
this[module] = {};
for (const api in apiConfig[module]) {
if (apiConfig[module].hasOwnProperty(api)) {
this[module][api] = this.executor.execute(apiConfig[module][api]);
}
}
}
}
}
}
exports.Index = Index;
//# sourceMappingURL=index.js.map
I've managed to get a fairly complex setup (though that's a question for Code Review) for my mixins that looks like this:
TooManyCaps.js
module.exports = {
labelCopyCaps: () => {
if (this.release.tracks.length > 1) {
if (_this._notEnoughLowercase(this.release.title)) {
this._recordError(release, 'LABELCOPYCAPS');
} else {
this.release.tracks.some( (track) => {
if (this._lowerCaseCount(track.label_copy)) {
this._recordError(release, 'LABELCOPYCAPS');
return true;
}
});
}
}
},
_notEnoughLowercase: (str) => {
if ((str.match(/[a-zA-Z]/g)||[]).length > 3
&& str.length - str.replace(/[a-z]/g, '').length) {
return true;
}
return false;
}
};
I then have an Object that would use this as a mixin:
Rule.js
class Rule {
constructor(release) {
this.release = release;
this.errors = [];
}
_recordError(error, options) {
this.errors.push({
release_id: this.release.id,
rule: error,
options: options,
});
}
}
module.exports = Rule;
i then have an index page that joins them together
index.js
const TooManyCaps = require('./TooManyCaps');
const Rule = require('./Rule');
Object.assign(Rule.prototype, [TooManyCaps]);
module.exports = Rule;
And then my main start of the program that does some instantiating of things:
'use strict';
const RuleValidator = require('./job/validation/RuleValidatorMixin');
const Rule = require('./job/validation/rulesmixins/rules/index');
// some logic that's a loop
arr.forEach((value) => {
new RuleValidator(new Rule(value)).validate();
}
and within validate() I have:
validate() {
console.log('VALIDATE');
this.rule.labelCopyCaps();
// console.log(this.rule);
}
But then when I run this, I get:
this.rule.labelCopyCaps is not a function
So where have i gone wrong?
Object.assign does not take an array:
Object.assign(Rule.prototype, [TooManyCaps]);
// ^ ^
should be just
Object.assign(Rule.prototype, TooManyCaps);