Skip to content
This repository was archived by the owner on May 1, 2020. It is now read-only.

Commit b5e82d0

Browse files
committed
Initial commit
0 parents  commit b5e82d0

File tree

8 files changed

+266
-0
lines changed

8 files changed

+266
-0
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
end_of_line = lf
5+
insert_final_newline = true
6+
trim_trailing_whitespace = true
7+
charset = utf-8
8+
indent_style = space
9+
indent_size = 2

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/node_modules/
2+
/out/
3+
/npm-debug.log
4+
5+
deploy_key

.travis.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
language: node_js
2+
node_js:
3+
- stable
4+
script:
5+
- bash ./deploy.sh
6+
env:
7+
global:
8+
- ENCRYPTION_LABEL: ""
9+
- COMMIT_AUTHOR_EMAIL: "d@domenic.me"

LICENSE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright © 2017 Domenic Denicola
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# import.meta
2+
3+
This repository contains a proposal for adding an `import.meta` metaproperty to JavaScript, for holding host-specific metadata about the current module. It is currently in stage 0 of [the TC39 process](https://tc39.github.io/process-document/).
4+
5+
Previously this problem space was discussed with the module-loading community in [whatwg/html#1013](https://github.com/whatwg/html/issues/1013). The result was a presentation at the May 2017 TC39 meeting of [these slides](https://docs.google.com/presentation/d/1p1BGFY05-iCiop8yV0hNyWU41_wlwwfv6HIDkRNNIBQ/edit?usp=sharing). The committee's feedback about the options presented there led to the particular form chosen in this proposal; these discussions are summarized in the rest of this README.
6+
7+
You can view the in-progress [spec draft](https://domenic.github.io/proposal-import-meta/) and take part in the discussions on the [issue tracker](https://github.com/domenic/proposal-import-meta/issues).
8+
9+
## Motivation and use cases
10+
11+
It is often the case that a host environment can provide useful module-specific information, to code evaluating within a module. Several examples follow:
12+
13+
### The module's URL or filename
14+
15+
This is provided in Node.js's CommonJS module system via the in-scope `__filename` variable (and its counterpart `__dirname`). This allows easy resolution of resources relative to the module file, via code such as
16+
17+
```js
18+
const fs = require("fs");
19+
const path = require("path");
20+
const bytes = fs.readFileSync(path.resolve(__dirname, "data.bin"));
21+
```
22+
23+
Without `__dirname` available, code like `fs.readFileSync("data.bin")` would resolve `data.bin` relative to the current working directory. This is generally not useful for library authors, which bundle their resources with their modules which could be located anywhere relative to the CWD.
24+
25+
Very similar use cases exist in browsers, where the URL would stand in place of the filename.
26+
27+
### The initiating `<script>`
28+
29+
This is provided in browsers for classic scripts (i.e. non-module scripts) via the global `document.currentScript` property. It is often used for configuration of an included library. The page writes code such as:
30+
31+
```html
32+
<script data-option="value" src="library.js"></script>
33+
```
34+
35+
and the library then looks up the value of `data-option` via code like
36+
37+
```js
38+
const theOption = document.currentScript.dataset.option;
39+
```
40+
41+
As an aside, the mechanism of using an (effectively) global variable for this, instead of a lexically-scoped value, is problematic, as it means the value is only set at top-level, and must be saved there if it is to be used in any asynchronous code.
42+
43+
### Am I the "main" module?
44+
45+
In Node.js, it is common practice to branch on whether you are the "main" or "entry" module for a program, via code such as:
46+
47+
```js
48+
if (module === process.mainModule) {
49+
// run tests for this library, or provide a CLI interface, or similar
50+
}
51+
```
52+
53+
That is, it allows a single file to serve as a library when imported, or as a side-effecting program when run directly.
54+
55+
Note how this particular formulation relies on comparing the host-provided scoped value `module` with the host-provided global value `process.mainModule`.
56+
57+
### Other miscellaneous use cases
58+
59+
Other cases that can be envisioned include:
60+
61+
- Other Node.js utilities, such as `module.children` or `require.resolve()`
62+
- Information on the "package" a module belongs to, either via Node.js's package.json or a [web package](https://github.com/dimich-g/webpackage)
63+
- A pointer to the containing DocumentFragment for JavaScript modules embedded inside [HTML modules](https://docs.google.com/presentation/d/1ksnC9Qr3c8RwbDyo1G8ZZSVOEfXpnfQsTHhR5ny9Wk4/edit#slide=id.g1c508fcb31_0_17).
64+
65+
## Constraints
66+
67+
Given that this information is so often host-specific, we want JavaScript to provide a general extensibility mechanism that hosts can use, instead of requiring standardization in JavaScript for every piece of metadata.
68+
69+
Also, as alluded to above, this is information is best provided lexically, instead of via e.g. a temporarily-set global variable.
70+
71+
## Proposed solution
72+
73+
This proposal adds an `import.meta` meta-property, which is itself an object. The object can be modified arbitrarily by the host, but by default it is an ordinary object, including having `Object.prototype` in its prototype chain.
74+
75+
The `import.meta` meta-property is only syntactically valid in modules, as it is meant for meta-information about the currently running module, and should not be repurposed for information about the currently-running classic script.
76+
77+
## Example
78+
79+
The following code uses a couple properties that we anticipate adding to `import.meta` in browsers:
80+
81+
```js
82+
(async () => {
83+
const response = await fetch(new URL("../hamsters.jpg", import.meta.url));
84+
const blob = await response.blob();
85+
86+
const size = import.meta.scriptElement.dataset.size || 300;
87+
88+
const image = new Image();
89+
image.src = URL.createObjectURL(blob);
90+
image.width = image.height = size;
91+
92+
document.body.appendChild(image);
93+
})();
94+
```
95+
96+
When this module is loaded, no matter its location, it will load a sibling file `hamsters.jpg`, and display the image. The size of the image can be configured using the script element used to import it, such as with
97+
98+
```html
99+
<script type="module" src="path/to/hamster-displayer.mjs" data-size="500"></script>
100+
```
101+
102+
## Alternative solutions explored
103+
104+
There are a number of other ways of potentially supplying host-specific metadata. The main other avenues explored were:
105+
106+
### Using a particular module specifier
107+
108+
The idea here is that we already have a mechanism for obtaining context-specific values from the module system: importing them! In this case the syntax for obtaining these properties would be via top-level importing of some particular module specifier, such as
109+
110+
```js
111+
import { url, scriptElement } from "js:context";
112+
```
113+
114+
This fits well with the existing framework, and can be taken care of entirely on the host side, requiring no new ECMAScript proposals (since hosts have control over how module specifiers are interpreted). However, on the web, it saw [opposition from WebKit](https://github.com/whatwg/html/issues/1013#issuecomment-281863721), and given TC39 was not unamimously united behind this idea, it was deemed not worthwhile trying to overcome WebKit's objection. Node.js may still implement this, especially if `import.meta` is not available soon enough for their needs.
115+
116+
### Introducing lexical variables in another way
117+
118+
This possibility would introduce the appropriate information as variables somehow injected into the scope of the module, similar to how Node.js currently injects `__dirname`, `__filename`, and `module`. Then they would just be used as normal in-scope variables:
119+
120+
```js
121+
console.log(moduleURL);
122+
console.log(moduleScriptElement);
123+
```
124+
125+
From an implementation and spec perspective, this could be done with no ECMAScript spec changes by, for example, the host prepending appropriate variable declarations to every module source text before handing it off to the ECMAScript spec mechanisms. Alternately, the host could introduce a new type of module record that has a slightly different scope for its [[Environment]] field. (Or ECMASCript could be modified to allow hosts to intervene in setting up the [[Environment]] of a source text module record.)
126+
127+
The committee was generally against handling this idea in ECMAScript as several members were not a fan of "polluting" module scopes with new variables. It remains a fallback option for web hosts if `import.meta` fails to advance quickly enough.

deploy.sh

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/bin/bash
2+
set -e # Exit with nonzero exit code if anything fails
3+
4+
SOURCE_BRANCH="master"
5+
TARGET_BRANCH="gh-pages"
6+
7+
function doCompile {
8+
npm run spec
9+
}
10+
11+
# Pull requests and commits to other branches shouldn't try to deploy, just build to verify
12+
if [[ "$TRAVIS_PULL_REQUEST" != "false" || "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]]; then
13+
echo "Skipping deploy; just doing a build."
14+
doCompile
15+
exit 0
16+
fi
17+
18+
# Save some useful information
19+
REPO=`git config remote.origin.url`
20+
SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:}
21+
SHA=`git rev-parse --verify HEAD`
22+
23+
# Get the deploy key by using Travis's stored variables to decrypt deploy_key.enc
24+
ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key"
25+
ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv"
26+
ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR}
27+
ENCRYPTED_IV=${!ENCRYPTED_IV_VAR}
28+
openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in deploy_key.enc -out deploy_key -d
29+
chmod 600 deploy_key
30+
eval `ssh-agent -s`
31+
ssh-add deploy_key
32+
33+
# Clone the existing gh-pages for this repo into out/
34+
# Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply)
35+
git clone $REPO out
36+
cd out
37+
git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH
38+
39+
# Clean out existing contents
40+
git reset --hard
41+
42+
# Run our compile script
43+
cd ..
44+
doCompile
45+
46+
# Now let's go have some fun with the cloned repo
47+
cd out
48+
git config user.name "Travis CI"
49+
git config user.email "$COMMIT_AUTHOR_EMAIL"
50+
51+
# If there are no changes to the compiled out (e.g. this is a README update) then just bail.
52+
if [[ -z "$(git status --porcelain)" ]]; then
53+
echo "No changes to the output on this push; exiting."
54+
exit 0
55+
fi
56+
57+
# Commit the "changes", i.e. the new version.
58+
# The delta will show diffs between new and old versions.
59+
git add --all .
60+
git commit -m "Deploy to GitHub Pages: ${SHA}"
61+
62+
# Now that we're all set up, we can push.
63+
git push $SSH_REPO $TARGET_BRANCH

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"private": true,
3+
"name": "proposal-import-meta",
4+
"description": "import.meta proposal for JavaScript (build setup only)",
5+
"author": "Domenic Denicola <d@domenic.me> (https://domenic.me/)",
6+
"license": "MIT",
7+
"repository": "domenic/proposal-import-meta",
8+
"scripts": {
9+
"spec": "ecmarkup spec.html out/index.html --js out/ecmarkup.js --css out/ecmarkup.css",
10+
"watch": "ecmarkup --watch spec.html out/index.html --js out/ecmarkup.js --css out/ecmarkup.css"
11+
},
12+
"devDependencies": {
13+
"ecmarkup": "^3.11.2"
14+
}
15+
}

spec.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<pre class="metadata">
2+
title: import.meta
3+
status: proposal
4+
stage: 0
5+
location: https://domenic.github.io/proposal-import-meta/
6+
copyright: false
7+
contributors: Domenic Denicola
8+
</pre>
9+
<script src="ecmarkup.js" defer></script>
10+
<link rel="stylesheet" href="ecmarkup.css">
11+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/solarized_light.min.css">
12+
13+
<emu-intro id="introduction">
14+
<h1>Introduction</h1>
15+
16+
<p>Background explanatory material for this specification can be found in the <a href="https://github.com/domenic/proposal-import-meta">domenic/proposal-import-meta</a> repository. See also the <a href="https://github.com/domenic/proposal-import-meta/issues">issues</a> list.</p>
17+
</emu-intro>

0 commit comments

Comments
 (0)