How to / is it possible to ensure no internet access in JavaScript web application?

I have been interested in providing web apps that can be accessed from a website, but are used completely offline.
The reason for this is to prove that privacy is being protected at a technical level.
However, I have only been able to find a few solutions.

The obvious solution is to overwrite APIs that access the internet so that even external libraries can not access these.
This is more difficult than it seems, with just how many ways JavaScript can interact with other servers these days.
There is also the issue of making sure this code is executed before any external libraries. Otherwise, the external libraries can get access to these APIs before any global changes are made.

Nothing beats proper code reviews, but unless the entire web application is open source and popular enough to be checked by many developers, this isn’t really a good solution.

A better solution would be for users to have say an extension that watches for internet access and make sure it does not happen. This is possible with the dev tools, and isn’t too difficult if extensions are disabled, but is still a lot of effort, risk, and not easy for non-technical users.

In Electron apps, it does seem partially possible to block internet access, but it doesn’t block at the Node level:
https://stackoverflow.com/a/69620535/1764521

It does seem at this point, there are no easy solutions, and that doing the best possible at every stage is the best that could be done. I’d say that would be good enough from a developer’s perspective, but from the user’s perspective, I think it still seems a bit risky for sensitive data.

I have left my conversation below with AI below that tried finding solutions, which only resulted in only partially useful information. If anyone has any better solutions, please feel free to comment.

When create a PWA, is it possible to completely prevent internet access? If yes, how should this be done, especially in a way that the end user can trust?

No, it’s not possible to completely prevent internet access within a PWA itself. Here’s why:

  1. PWAs rely on browsers: PWAs are web applications that leverage browser functionalities. Browsers are inherently designed to access the internet, and limiting this function would go against their core purpose.
  2. Security concerns: Completely blocking internet access within a PWA raises significant security concerns. It would essentially create a closed environment, making it difficult to implement security updates, bug fixes, and new features. This could leave the PWA vulnerable to known and future exploits.

However, there are alternative approaches that can offer a similar user experience while maintaining transparency and trust:

1. Leverage Caching and Offline Functionality:

  • You can leverage the service worker API to cache essential app resources like data and static files. This allows the PWA to function partially even when offline.
  • Design the PWA to gracefully handle offline scenarios by informing users they’re offline and displaying appropriate UI elements like error messages or cached versions of content.

2. User-controlled Offline Mode:

  • Implement an optional “offline mode” toggle within the PWA. This allows users to choose to operate offline for specific features or functionalities.
  • Clearly communicate the limitations and functionality available in offline mode to build trust with users.

3. Emphasize Transparency:

  • Clearly state in the PWA’s description and store listing that it requires an internet connection for full functionality.
  • Be upfront about any limitations regarding offline capabilities.

Remember, the key is to provide a secure and reliable experience for users while remaining transparent about the PWA’s capabilities and limitations.

So there are no features in PWA manifest, service workers, or other APIs that allow for preventing internet access even if the PWA is locally stored?

You are correct. There are no features within the PWA manifest, service workers, or other Web APIs designed to completely prevent internet access for a PWA.

Here’s a breakdown of why:

  • PWA Manifest: The manifest file focuses on providing information about the PWA, such as its name, icons, and launch details. It doesn’t have functionalities related to controlling network access.
  • Service Workers: Service workers act as intermediaries between the PWA and the network. While they can manage caching and network requests, they cannot entirely block network access. Their purpose is to enhance the offline experience, not restrict it completely.
  • Web APIs: Web APIs provide functionalities for various tasks like fetching data, accessing sensors, and manipulating the UI. None of the standard Web APIs offer the ability to disable network access altogether.

It’s important to understand that PWAs rely on the browser environment, and browsers inherently have internet access as a core function. Restricting it within a PWA would not only be technically challenging but also potentially detrimental to the app’s functionality and security.

Are there not talks about this anywhere? Surely fully offline web apps are desired.

You’re right, there are ongoing discussions and explorations regarding the possibility of fully offline web applications. While completely preventing internet access within PWAs faces the limitations mentioned earlier, there are alternative approaches and ongoing efforts aiming to achieve a similar goal:

1. WebAssembly (WASM): WASM is a low-level assembly language that allows developers to compile code from various languages (like C++) and run it efficiently within web browsers. This opens the possibility of creating web apps that can bundle their own functionalities and data, potentially enabling offline usage to a greater extent.

2. Web App Manifest – “network_state” property (proposal): There’s an ongoing proposal to introduce a new property called “network_state” within the PWA manifest. This property, if implemented, could potentially allow developers to indicate the level of network connectivity required by the PWA. While it wouldn’t directly restrict access, it could inform users about potential limitations when offline and provide a more transparent experience.

3. Dedicated APIs for offline functionality: Discussions are happening regarding the potential for dedicated Web APIs that could enhance offline capabilities for web apps. These APIs could focus on functionalities like local data storage, synchronization, and background tasks, offering developers more tools to build robust offline experiences.

It’s important to note that these are ongoing discussions and proposals, and their implementation or final form may vary. However, they highlight the ongoing interest in and efforts towards providing better offline experiences and functionalities for web applications.

How about if I use Electron?

Electron offers a different approach compared to PWAs, and it can be used to create applications that function entirely offline. Here’s how:

Electron’s Offline Capabilities:

  • Bundled Application: Unlike PWAs that rely on the browser, Electron apps are self-contained, meaning they bundle all necessary resources (HTML, CSS, JavaScript, and other files) within the application package. This eliminates the need for internet access after the initial download and installation.
  • Native Functionality: Electron allows developers to access native system functionalities like file systems, local storage, and device hardware. This enables developers to create applications that can store data locally, perform tasks without requiring internet access, and offer a more desktop-like experience.

However, there are some trade-offs to consider:

  • Distribution complexity: Electron applications are not directly deployable through app stores like PWAs. They need to be packaged for specific operating systems and distributed through custom channels.
  • Platform dependency: Electron applications are native and run differently on various operating systems (Windows, macOS, Linux) compared to the cross-platform nature of PWAs. This means developers need to create and maintain separate codebases for different platforms.

Overall, Electron is a viable option if:

  • You prioritize complete offline functionality and native-like features.
  • You are comfortable with the complexities of building and distributing a desktop application.

If your primary focus is on:

  • Easy deployment and accessibility through web browsers.
  • Providing a web-based experience with enhanced offline capabilities, PWAs remain a valuable option.

Ultimately, the best approach depends on your specific project requirements and priorities.

However, in Electron, how is offline only proven to the user?

Proving that an Electron application functions entirely offline is a multifaceted process that involves a combination of technical considerations and user experience design:

1. Code Review and Testing:

  • Thorough code review: Conduct a comprehensive review of your application’s code to ensure there are no hidden dependencies on external resources or network calls. This involves verifying all functionalities and data access methods.
  • Offline testing: Rigorously test your application in a completely disconnected environment to simulate an offline scenario. This helps identify any unexpected behavior or potential issues related to missing resources.
  • Static code analysis tools: Utilize static code analysis tools to scan your codebase and identify potential network interactions or external dependencies that might not be readily apparent during manual review.

2. User Experience Design:

  • Clear communication: Inform users upfront about the app’s offline capabilities. This can be done through the application description, splash screen, or in-app messages.
  • Offline mode indicator: Implement a visual indicator like an icon or message to clearly communicate the app’s online/offline status to users.
  • Graceful handling of potential network issues: Handle potential network disruptions gracefully by displaying informative messages and providing alternative functionalities while offline.
  • Avoid misleading functionality: Avoid offering features or buttons that appear to be functional but are inoperable due to the lack of internet connection. Disable or gray out such features in offline mode.

3. Third-party library assessment:

  • Evaluate dependencies: If you utilize third-party libraries, carefully evaluate their potential network requirements. Opt for libraries with minimal dependencies or those explicitly designed for offline usage. Consider alternatives or implementing workarounds if necessary.

4. Documentation:

  • Provide clear documentation: Clearly document the application’s offline capabilities and limitations in the user manual or in-app help section. This helps users understand what to expect when using the app offline.

It’s important to remember that fully guaranteeing complete offline functionality can be challenging due to external factors like unforeseen updates or changes in the operating system or underlying libraries. However, by implementing these strategies, you can significantly increase user trust and confidence in your Electron application’s offline capabilities.

Is there nothing a bit clearer, such as a manifest property/permission?

Unfortunately, there isn’t a single, universally clear manifest property or permission in Electron that explicitly guarantees an application functions entirely offline. However, there are ongoing discussions and potential future advancements that might bring us closer to such a solution:

1. Declarative Net Request Permission (proposal): A proposal for a new API called “Declarative Net Request Permission” is under discussion. This API could potentially allow developers to declare their application’s network access requirements within the manifest file. While not a direct guarantee of offline functionality, it could provide a clearer indication to users about the app’s intended network usage.

2. Code signing and verification: While not a direct solution within Electron itself, advancements in code signing and verification technologies could offer a layer of trust to users. By cryptographically signing your application code and having it verified by a trusted authority, users could gain more confidence in the application’s integrity and potential offline capabilities.

It’s important to note that these are proposals and future advancements, and their implementation or final form is subject to change. However, they highlight the ongoing efforts to improve transparency and user trust regarding application behavior, including offline functionality.

For now, the strategies mentioned earlier, focusing on code review, testing, user experience design, and clear communication, remain the most effective ways to establish trust and confidence in your Electron application’s offline capabilities.

When editing in VSCode, if a JS file imports ESM exports from another a node_modules library, if that library is in JS, then type declarations are required for type hinting? If the node_modules library is in TS, are type declarations required for type hinting?

Here’s a comprehensive explanation:

When a JS file imports ESM exports from a Node.modules library:

  • If the library is in JS:

    • Type declarations are needed for type hinting in VS Code.
    • Methods to provide type declarations:
      1. Library-provided types:
        • Check if the library includes its own types, often in a @types or dist directory. Install them using npm or yarn.
      2. DefinitelyTyped:
        • Search for community-maintained types on DefinitelyTyped. Install using @types/<library-name>.
      3. Create manual type declarations:
        • If types aren’t available, create a .d.ts file with type definitions for the library’s exports.
  • If the library is in TypeScript:

    • Type declarations are typically not required.
    • VS Code can infer types directly from the library’s TypeScript code.

Key points for optimal type hinting experience:

  • Enable the TypeScript extension in VS Code.
  • Configure VS Code to discover type declarations:
    • Set typeRoots in jsconfig.json or tsconfig.json to include node_modules/@types.
  • Consider using a type checker for enhanced type safety and linting:
    • Explore ESLint with TypeScript plugins or standalone type checkers like TypeScript ESLint or tsc.

Additional tips:

  • Keep type declarations up-to-date:
    • Ensure they match library versions for accuracy.
  • Leverage VS Code’s IntelliSense for guidance:
    • Utilize code completion, hover information, and error checking for efficient coding.
  • Explore advanced features:
    • Type search (Cmd+T or Ctrl+T), go to type definition (F12), type hierarchy exploration, and more.

Why do I need a TypeScript declaration file for a JavaScript library even though type checking works in VSCode in own library?

The following is an AI chat conversation regarding the topic stated in the title.
Depending on the quality of the conversation, modifications may have been made. Modifications may or may not be stated in this page.


Why do I need to generate a declaration file for a javascript library in order to get type hinting in VSCode when I use that library in another project? VSCode can already get types of JS file in the same project. So why does this change when importing from an external library?

Here’s a breakdown of why declaration files are required for type hinting in VSCode when using external JavaScript libraries:

1. JavaScript’s Dynamic Nature:

  • JavaScript is dynamically typed, meaning type information isn’t explicitly included in the code itself. This flexibility makes it harder for editors to infer types accurately, especially for external code.

2. VSCode’s Type Hinting Reliance:

  • VSCode heavily relies on type information for features like:
    • IntelliSense (code completion, suggestions)
    • Hover information
    • Parameter and type checking
    • Refactoring tools

3. Separate Project Scope:

  • When a library is in a separate project, VSCode can’t directly analyze its source code to infer types. Declaration files (.d.ts) bridge this gap.

4. Declaration Files:

  • They describe the types of variables, functions, and classes within a library.
  • They’re written in TypeScript, a superset of JavaScript with explicit typing.
  • VSCode can leverage them for type hinting even in JavaScript projects.

5. Type Acquisition Methods:

  • Automatic: VSCode tries to automatically fetch declaration files for popular libraries.
  • Manual: Install declaration files from DefinitelyTyped (a community repository): npm install --save-dev @types/<library-name>
  • Generating: Compile a library’s TypeScript source code or use tools to create .d.ts files from JSDoc comments.

Key Points:

  • Declaration files are essential for type-aware features in VSCode when using external JavaScript libraries.
  • They make your code more readable, maintainable, and less prone to type-related errors.
  • Consider using TypeScript for new projects to enjoy strong typing and type safety from the start.

The HTMLMediaElement (

The HTMLMediaElement (Mainly <video> and <audio>) contains a “volume” property.
This property is set by the browser and seems to have a default value of max (1.0).
This “volume” property can be modified via JavaScript, by simply set a valid value between 0 and 1.
It seems that it is sometimes altered on videos such as in YouTube adverts.
The reason for this is described in the AI conversation I shared below. To summarize, advert owners seem to have the ability to change the volume.


The following is an AI chat conversation regarding the topic stated in the title.
Depending on the quality of the conversation, modifications may have been made. Modifications may or may not be stated in this page.


There is a “volume” property on HTMLMediaElement elements. It can be modified. When playing a YouTube video, I checked the value, and it was 0.4415704270182424. Is this value the default value? Can this value be changed at a browser or browser extension level? Can this value be changed at an OS level? Why is this valued used, and not a max value of 1?

No, the value you observed (0.4415704270182424) is not the default value for the volume property on HTMLMediaElement elements. The default value is 1.0, which represents the maximum volume.

Here’s a breakdown of your questions:

Can this value be changed at a browser or browser extension level?

  • Yes, the volume property can be changed through both browser settings and browser extensions. Browsers usually have volume controls built-in, and many extensions offer additional functionalities like volume normalization or specific volume adjustments for certain websites.

Can this value be changed at an OS level?

  • Yes, most operating systems have system-wide volume controls that apply to all applications, including web browsers. Adjusting the system volume will also affect the volume of HTML media elements.

Why is this value used, and not a max value of 1?

There are a few reasons why the specific value you encountered might not be 1.0:

  • Initial volume setting: Some websites or video players might have a different initial volume setting than the browser default.
  • User interaction: The user might have previously adjusted the volume using the browser controls, an extension, or the system volume, resulting in the value you observed.
  • Automatic volume adjustments: Certain browser extensions or system settings might automatically adjust the volume based on various factors like ambient noise level or user preferences.

It’s important to note that while the volume property technically allows values between 0 (muted) and 1 (maximum), some browsers or extensions might use a different scale or apply additional logic, potentially leading to non-intuitive values like the one you observed.


The value was that when viewing an advert on YouTube. Was the value that because of being on YouTube, or the advert?

The observed value (0.4415704270182424) for the volume property in your case is likely not directly caused by being on YouTube itself, but rather due to the specific advertisement you were watching or previous user interaction. Here’s why:

  1. YouTube doesn’t automatically adjust volume: While some websites might have their own initial volume settings, YouTube itself doesn’t have a known feature that automatically adjusts the volume for specific content like advertisements.

  2. Advertisers control their content: Advertisements on YouTube are uploaded by individual companies or agencies. These entities have control over the audio levels within their ads, which could explain the specific volume level you observed.

  3. Past user interaction: As mentioned earlier, the volume property could have been previously adjusted through browser controls, extensions, or system settings, impacting the value you saw even during the ad.

Therefore, the specific value you encountered is more likely a combination of:

  • The volume level set within the advertisement itself.
  • Any previous volume adjustments you or your system made.

It’s important to note that while there are no regulations directly mandating specific volume levels for online advertisements, many users find sudden changes in volume disruptive. YouTube itself offers a feature called “Stable volume” that aims to reduce volume fluctuations between videos and ads. However, it’s ultimately left to individual advertisers to be mindful of their ad’s audio levels to create a positive user experience.

Tree shaking ES6 JavaScript code. Does tree-shaken bundle of single named export contain others of that file?

The following is an AI chat conversation regarding the topic stated in the title.
Depending on the quality of the conversation, modifications may have been made. Modifications may or may not be stated in this page.


When tree shaking ES6 JavaScript code, if I import a single named function from a file that exports multiple named functions, will the tree shaken code still contain the other named functions?

No, in most cases, tree shaking will remove the unused named functions from the final code. Here’s how it works:

  1. Static Analysis: Tree shaking tools like Webpack or Rollup analyze the module’s import statements. They create a dependency graph, mapping which exported functions are actually used by other modules.

  2. Unused Code Elimination: If a named function is not imported anywhere, tree shaking removes it from the final bundle. Only the necessary code for used functions is included.

Example:

JavaScript
// math.js
export function add(x, y) { return x + y; }
export function subtract(x, y) { return x - y; }

// main.js
import { add } from './math.js';

console.log(add(2, 3));
  • After tree shaking, subtract will be removed from the final code, as it’s not imported in main.js.

Important Considerations:

  • Tree shaking is most effective with direct named imports: While it generally works with named imports, it might be less effective with default imports or complex module structures.
  • Side Effects: Tree shaking cannot remove functions that have side effects, like modifying global state or accessing external resources, even if they’re not directly used. The bundler assumes they might be necessary for the application to function correctly.

Tips for Effective Tree Shaking:

  • Use named imports whenever possible.
  • Be mindful of side effects in exported functions.
  • Consider using bundler options like sideEffects: false in package.json to provide hints about modules that can be fully tree-shaken.
  • Use tools like Webpack Bundle Analyzer to visualize the generated bundle and identify optimization opportunities.

Research notes regarding converting JSDoc to TypeScript types

A lot of my JS code had been typed with JSDoc comments.
JSDoc comments are very useful for typing JavaScript code, and also have the benefit of allowing inline TypeScript types and importing TypeScript types from ts files. Types can be checked easily in modern editors such as VSCode. For example, the code below, imports from a ts file and types the variable.

/**
* @type {import('tsfile.ts').MyType}
*
const myVariable = 'abc';

It is also possible to declare the type using @typedef to reuse within the file.

/**
* @typedef {import('tsfile.ts').MyType} MyType
*

/*
* @type {MyType}
*/
const myVariable = 'abc';

However, one big issue with JSDoc is that importing it from external libraries seems to not work.
TypeScript types seem to be usable without any processing by just referencing the file such as:

/**
* @typedef {import('my-library'/ts-file-location.ts).MyType} MyType
*/

For JSDoc, generate type declaration files seems to be required.
This is fine, and is expected for JS projects, but it is an extra step that needs to be prepared for all JS projects.

Considering, TypeScript can be imported into JSDoc in the first place, there is really no reason to store type files using JSDoc. The solution is then to isolate types into type only files in ts, and then export each type. This makes it easy to import into JSDoc and into other projects without and processing.

Searching for solutions to convert JSDoc to TypeScript did take my down and long-winding road of issues, that seems to not have been worth the trouble. I have written any significant information in the notes below, but the solution is to just use tsc from TypeScript. See below.

TypeScript tsc

  • Seems to work best. Just need to add exports if necessary and extract from generated file(s).
# Update [SOURCE] below.
# tsc [SOURCE] --declaration --emitDeclarationOnly --allowJs
#
# Notes:
# -- outFile [BUNDLE_DESTINATION] // Works for only some code, so use optionally. https://www.typescriptlang.org/tsconfig/#outFile
# .d.ts file is created in same location with same name before extension.
# To create ts file with exports, SHOULD remove the ".d" part for declaration file, and replace each "type " with "export type ".
# MAY do the same for "interface", but seems like not used (maybe if specifically specified in JSDOC as interface?).
# To prevent replacing wrong code within comments/strings, etc., check that "type" starts at beginning of line.

Notes

ts-migrate

ts-fix

TypeScript codefixes

Other

When the URL of an iframe is changed within the iframe, the iframe element’s “src” attribute does not change. What is the reasoning for this?

I asked Bard AI about why iframes don’t update the src attribute when the content changes, and got a very logical response.

Thinking about it, one obvious point is that the content within the iframe should not leak any data in the page. This is because in the iframe, the content may include something like an OAuth login, or query state. It is possible that the query parameters could contain something like an OAuth code or sensitive search queries, which should definitely not be shared with the parent DOM.

The full response is below.

There are a few reasons why the iframe element’s src attribute does not change when the URL of an iframe is changed within the iframe.

First, it is important to remember that an iframe is a separate document from the parent document. When you change the URL of an iframe within the iframe, you are actually changing the URL of the embedded document, not the iframe element itself.

Second, the src attribute of an iframe element is read-only. This means that once the src attribute is set, it cannot be changed.

Finally, there is a security risk associated with allowing iframes to change their own src attribute. If an iframe were able to change its own src attribute, it could potentially load malicious content from a different domain.

To avoid these problems, if you need to change the URL of an iframe, you must do so from the parent document. You can do this using JavaScript to set the src attribute of the iframe element.

Here is an example of how to change the URL of an iframe using JavaScript:

JavaScript
// Get the iframe element
var iframe = document.getElementById('myIframe');

// Set the src attribute of the iframe element
iframe.src = 'https://new-url.com';

When you set the src attribute of an iframe element using JavaScript, the iframe will be reloaded with the new URL.

It is important to note that you can only change the URL of an iframe if the iframe is from the same domain as the parent document. If the iframe is from a different domain, you will need to use a cross-origin resource sharing (CORS) request to change the URL of the iframe.

How to mark an npm project as for Node.js or for browser or for both?

One issue I have often run into when using npm packages is not supporting the browser.
It is common for even a simple utility package to have a dependency on an npm package and so only work in Node.js. It would be nice if this could be detected quickly, especially automatically.
I asked this question to Bard AI, and got a useful response. The response doesn’t solve the issue for all packages as it requires certain optional properties to be set, but if they are set, then it can be decided what environment support exists.

Is there a common or official way to mark an npm project as for usage of Node.js(not browser), vice-versa, and both?

Yes, there are two ways to mark an npm project as for usage of Node.js (not browser), vice-versa, and both.

  • Using the engines field in the package.json file. This is the official way to specify the runtime environment that a package requires. The engines field is a list of objects, each of which specifies a minimum version of a particular runtime environment. For example, to specify that a package requires Node.js 16 or later, you would add the following to the engines field:
"engines": {
  "node": ">=16"
}
  • Using the browserslist field in the package.json file. This field specifies the browsers that a package supports. If you want to specify that a package is only for Node.js, you would set the browserslist field to an empty array. For example:
"browserslist": []

If you want to specify that a package is for both Node.js and the browser, you would set the browserslist field to a list of browsers that the package supports. For example:

"browserslist": ["last 2 versions", "not ie <= 11"]

The browserslist field is used by the npm command to determine which packages to install when you run npm install. For example, if you have a package that is only for Node.js, and you run npm install, the npm command will only install the packages that are listed in the engines field.

I hope this helps! Let me know if you have any other questions.