In deno you can load related modules or other code by just referencing the relative path to those ES6 modules. Deno will handle loading them appropriately. What's the way to do this for non-es6 modules? For example: say I wanted to include some custom css with my deno project? Deno doesn't allow doing import mycss from "./relative.css";.
Deno file operations do work for local files, but they're evaluated relative to the cwd not the current file, and they don't work for arbitrary URLs. fetch, on the other hand, should be perfect, but currently doesn't support file schemes and the decision isn't being actively considered. Combining these yields the only solution I can come up with, but I really don't like it:
async function loadLocal(relative: string): Promise<string> {
const url = new URL(relative, import.meta.url);
if (url.protocol === 'file:') {
return await Deno.readTextFile(url.pathname);
} else {
const resp = await fetch(url.href);
return await resp.text();
}
}
This seems like it should mostly work, but it seems like a terrible way to hack in something that I expected would be supported by design in deno. It also must be redeclared in each file, or have the callers URL passed in, although there might be a way to avoid that. It doesn't work on windows without modifying the path delimiter.
Update
Deno.emit seems close to what I would want, however for some reason it has different behavior than standard importing:
If the rootSpecifier is a relative path, then the current working directory of the Deno process will be used to resolve the specifier. (Not relative to the current module!)
It also still requires that the paths be to valid modules, instead of arbitrary text.
As #Zwiers pointed out, deno 1.6 now supports fetch with the file protocol, so this is now irrelevant.
Related
I'm writing a nuxt module following this guide.
Now I would like my module to add a proxy rule to the host application. Its a lot of guesswork and nothing has done the trick so far. I tried
nuxt.options.proxy.options.push(
{
target: 'https://target-url.com',
changeOrigin: true,
pathFilter: ['path/to/match']
}
)
}
but my IDE complains that proxy is not a known property of NuxtOptions. I did shorten the above code for the sake of this post. In my code I also made sure the respective objects exist before assigning something to them.
next best guess (based on the example for adding a css library) was to do the same thing, but on the runtimeConfig like so:
nuxt.options.runtimeConfig.proxy.options.push(...)
no complaints by the IDE anymore (duh, the runtimeConfig object is of type any) but no sign of the proxy actually working.
I build a rest service in Deno (Oak) and also serve static files. However, when I run deno compile I would like to have those static files included into the single binary file that is ejected. Is this possible?
From what I can tell, neither Deno nor Oak have intentional support for this.
A downside of even doing this is that your binary file may become large. This isn't only an issue with distribution but may also slow loading and executing the binary.
Nevertheless, one way you can make "static" files available in a compiled binary is to encode the files as JavaScript modules (similar to using WebAssembly in Deno).
e.g. The following module encodes a static file, named example.txt, storing its file type, txt, and its contents, hello world\n. The contents are base64 encoded (thank you jsejcksn for the suggestion). You can encode and decode the contents other ways as well or even use different encodings depending on the file type if you like.
example.txt.ts:
export default {
type: "txt",
data: "aGVsbG8gd29ybGQK",
};
You can programmatically create modules like this from static files.
e.g. encode-as-module.ts:
import { extname } from "https://deno.land/std#0.155.0/path/mod.ts";
import { encode } from "https://deno.land/std#0.155.0/encoding/base64.ts";
const [inputPath, outputPath = `${inputPath}.ts`] = Deno.args;
const type = extname(inputPath).slice(1);
const bytes = await Deno.readFile(inputPath);
const script = /* JavaScript */ `export default {
type: "${type}",
data: "${encode(bytes)}",
};
`;
await Deno.writeTextFile(outputPath, script);
Usage:
deno run --allow-read --allow-write encode-as-module.ts example.txt
Once you have your static files encoded as modules you can then change your Oak app from serving them using send() to serving them using context.response (passing the type and body). More work will need to be done here to encode a list of all the static files, etc. but I think what's already provided here illustrates the idea sufficiently.
Barrel/index files seem to create issues when used with next.js. It doesn't seem established if it's purely a webpack issue or both webpack and next.js
According to this issue tree shaking stops working if we use barrel files. I also created a small repo where I have an issue with an index file. Not sure if it's a tree shaking issue.
Steps to reproduce the issue:
npm install
npm run dev
in browser, visit http://localhost:3000/about-pro, expect to see blank page with errors or warnings in browser's console
go to server's console(where you run npm run dev)
see an error of sort "Module not found: Can't resolve 'fs'" (1) (2) (3)
1- this comes from the await serialize in getAboutPageData file. Which itself is only called within getStaticProps
2 - googling for this issue, you'll find solutions such as modifying next.config.js file. It still doesn't work. Feel free to uncomment the next.config.js file and see for yourself
3 - to "solve" the issue, go to about-pro.tsx, in the imports, import AboutPage from its own file instead of from the barrel/index file
If I only import getAboutPageData from the barrel/index file, then it works fine. But as soon as I import e.g. AboutPage from it, it starts throwing unrelated issues.
Can I continue using barrel/index files with next.js and if yes, is there a simple and intuitive way to do that?
The issue is not in the barrel files themselves but in the library that you're using combined with barrel files.
If you take a look at the readme file https://github.com/hashicorp/next-mdx-remote#examples you can find a warning:
IMPORTANT: Be very careful about putting any mdx-remote code into a separate "utilities" file. Doing so will likely cause issues with nextjs' code splitting abilities - it must be able to cleanly determine what is used only on the server side and what should be left in the client bundle. If you put mdx-remote code into an external utilities file and something is broken, remove it and start from the simple example above before filing an issue.
So in order to make your code work you need to remove the export of getAboutPageData from your barrel file, like this:
export { default as AboutPage } from './AboutPage';
// export { default as getAboutPageData } from './getAboutPageData';
and move the code that uses the library inside the about-pro.tsx file.
import { AboutPage } from '../modules/about';
import { serialize } from 'next-mdx-remote/serialize';
const AboutPro = (props) => {
return <AboutPage {...props} />;
};
export const getStaticProps = async () => {
const serializedContent = await serialize(`# Header1`);
const data = serializedContent;
return { props: {} };
};
export default AboutPro;
I think the issue is that the modules imported in barrel files are executed both client and server side. Probably removing side effects from the barrel file could solve the issue, but I don't know enough about Next.js to be able to do it correctly.
The following code works to load a local, static JSON file:
var stories = require('../stories/stories.json');
Now I want to load a file based on a variable, e.g. do something like this:
var storiesPath = '../stories/stories.json';
var stories = require(storiesPath);
But this triggers an error:
Error: Cannot find module '../stories/stories.json'
at require (packages/modules-runtime.js:123:19)
at meteorInstall.server.main.js (server/main.js:7:15)
Is there any way to get this working? I assume that I could load my file via the Meteor http package instead but I'd rather not add another package if I can avoid it.
Thanks for your hints
Like I said in the comment, you can easily use a variable in a require, e.g.,
> var x = 'fs';
> require(x).readFile
[Function]
So that's not the problem you are dealing with. Are you sure your first case indeed works? It would be surprising. I think you might be running into project file layout issues, due to the use of a relative path. I would stay away from that. And fortunately you can quite easily by using an asset! You can put your json file in private/ in your project folder and then use:
const stories = JSON.parse(Assets.getText('stories.json'));
I'm writing an nginx module.
From looking at other examples I'm registering my header filter in my modules postconfiguration hook:
static ngx_int_t
mod_py_postconfig(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = mod_py_headers_filter;
return NGX_OK;
}
But the handler is never called. I've set a breakpoint in gdb on ngx_http_top_header_filter change and it seems my module's postconfig is called first, but then runs postconfig of the ngx_http_write_filter_module which overrides ngx_http_top_header_filter w/o storing the old value:
static ngx_int_t
ngx_http_write_filter_init(ngx_conf_t *cf)
{
ngx_http_top_body_filter = ngx_http_write_filter;
return NGX_OK;
}
it seems like it is designed to be the very last on called, so how come my module's postconfig is called first?
From what I can see the order of modules is set in objs/ngx_modules.c
I was able to fix the problem by manually reordering the modules there so that my module comes after ngx_http_header_filter_module, but this feels like an ugly hack, and also makes it hard to automate build process as ./configure overwrites this file each time.
OK, so I figured it out myself. Documenting it here in case anyone else will need it.
I was adding my module to the wrong list. The nginx module is configured through a 'config' file insed module's directory. My had the following line in it:
HTTP_MODULES="$HTTP_MODULES ngx_http_my_module_name"
I searched for HTTP_MODULES usage and found nginx/auto/modules script which actually builds ngx_modules.c file. It turns out there are several possible module lists used by nginx/auto/modules. I needed to add my module to the HTTP_AUX_FILTER_MODULES list like so:
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_my_module_name"
This placed my module at the right place just after HTTP_HEADERS_FILTER_MODULE and fixed the problem.