-
Notifications
You must be signed in to change notification settings - Fork 513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Project] Produce standalone ES6 modules. #2292
Comments
I don't have yet an opinion on all these topics, but marking non-module-level imports as incorrect is not possible, because the Python language supports them and by design Brython is as compliant as possible with Python. In the Brython standard library only, these scripts have such imports: ['_codecs.py', '_dummy_thread.py', '_frozen_importlib.py', '_pydatetime.py', '_pydecimal.py', '_socket.py', '_sre.py', '_thread.py', '_typing.py', 'argparse.py', 'ast.py', 'base64.py', 'bdb.py', 'calendar.py', 'cmd.py', 'code.py', 'codecs.py', 'collections\init.py', 'concurrent\futures\process.py', 'copy.py', 'copyreg.py', 'difflib.py', 'doctest.py', 'email\utils.py', 'encodings\init.py', 'encodings\rot_13.py', 'enum.py', 'functools.py', 'getopt.py', 'getpass.py', 'gettext.py', 'gzip.py', 'heapq.py', 'hmac.py', 'http\client.py', 'imp.py', 'importlib\init.py', 'importlib\_bootstrap.py', 'importlib\_bootstrap_external.py', 'importlib\abc.py', 'inspect.py', 'ipaddress.py', 'json\init.py', 'locale.py', 'logging\init.py', 'logging\config.py', 'logging\handlers.py', 'mimetypes.py', 'multiprocessing\util.py', 'nntplib.py', 'ntpath.py', 'os.py', 'pathlib.py', 'pdb.py', 'pickle.py', 'pkgutil.py', 'posixpath.py', 'profile.py', 'py_compile.py', 'pydoc.py', 'quopri.py', 're1.py', 'select.py', 'shutil.py', 'site-packages\simpleaio\helpers.py', 'site.py', 'socket.py', 'subprocess.py', 'symtable.py', 'sysconfig.py', 'tabnanny.py', 'tarfile.py', 'threading.py', 'time.py', 'timeit.py', 'tokenize.py', 'traceback.py', 'types.py', 'typing.py', 'unittest\init.py', 'unittest\main.py', 'unittest\loader.py', 'unittest\mock.py', 'urllib\parse.py', 'uu.py', 'uuid.py', 'warnings.py', 'weakref.py', 'zipfile.py'] |
I can isolate some "sub-steps", that can still be interesting to do regardless of the whole global scheme.
It is not exactly marking them as "incorrect", but notifying users that it might not be supported in the future due to the evolution of Web standards, independently of Python/Brython. But yeah I understand your point. |
Okay, some stuff that can be interesting regardless :
This would enable some level of integration with current WebDev tools... Well, won't be as performant as an ES6 output for tree shaking, but still, can be an easy step to be able to use some nice features (e.g. advanced Bundling). Modules would then be loaded in Brython thanks to Still, could be nice to be able to just include them as Could be the firsts steps in this project, then the only remaining tasks would be :
@PierreQuentel What do you think now ? EDIT:
let singleton = null;
function X(){ // the original (function(){}) here:
// ...
}
export default function FOO() {
if( singleton !== null)
return singleton
return singleton = X();
}
if( __BRYTHON__.__IN_IMPORT__ !== true ) // if included in a <script>, execute it immediately.
FOO();
// at the top of the files:
const orig = __BRYTHON__.__IN_IMPORT__
__BRYTHON__.__IN_IMPORT__ = true
// only if resolved during build time:
import MODULE_A from './path_to_module_A'; // pre-import without executing it.
__BRYTHON__.__IN_IMPORT__ = orig
// the generated JS stuff
// ...
// replace top level imports resolved during build time by:
MODULE_A(); // execute it now (only when we need it).
__BRYTHON__.getPythonModule(module_name); // do stuff the Brython way.
// ...
// end of the generated JS stuff With that we can now use tools like Parcell, Webpack, etc. If the format mode is ES6, then it could simply replace Python top level import resolved during build time, by JS top level import. EDIT2: Instead of a // do eventually some stuff
function FOO(){} // the generated main function.
__BRYTHON__.addModule(FOO); // will execute FOO at the correct time to add the module With that, no needs for a top level await. |
|
If it is only for TOP-level import, you can do TOP-level JS await (if webworker are constructed with But that's not a hill I'll die on xD.
I suggested 2 output formats. The second one is doing nearly what The advantage compared to
Still, I think Brython should at least add a For example, the following code won't work:
Maybe also add a Note: it seems there is a bug in the documentation example for
|
Hello, really interesting issue to follow, I'm specially interested in async imports. Regarding non top level imports, it can be sometimes useful to use them to save resources (e.g. you need to import an heavy module only if some dynamically known condition are met). What about doing a Brython specific async |
You're right, the error happens if there is nothing in the INPUT field, or if |
… Suggested by Denis Migdal in issue #2292.
? You can already do that in Python/Brython. Just put the import inside a function, or use importlib ? |
…ipt> element. Related to issue #2292.
Good idea Denis ! In the commit above I have added a new core Brython script, With the following commit (abed0fb) you can test that the script is available with document.getElementById('s1').addEventListener('load',
function(ev){
var v = document.getElementById('num').value
__BRYTHON__.getPythonModule('s1').show_square(parseInt(v))
}
) |
Thanks, I'll take a look at it tomorrow ;) |
I may have missed something, but I thought that non top level import were about to be deprecated with Brython:
And my suggestion was to replace blocking import by a Brython specific async |
No, it's standard Python so it will remain supported in Brython. |
Synchronous import currently relies on synchronous AJAX that are depreciated (but still implemented by browser).
Well we have no issue with async |
Indeed, I'm aware of the situation, and it's really good that you anticipate this (also good from a performance point of view).
Does it? I though that everything was blocking there, and after a quick glance at the doc, I haven't seen anything mentioning async import. |
Let's keep things simple. Brython is as compliant with standard Python as possible, so importing Python modules / packages is done with the keyword In any case, if there was a need to import Python code asynchronously in Brython, it would be with a different syntax from the For Javascript code
|
I have a third advantage to add: It would allow brython to be used to write browser extensions with manifest v3. Manifest 2 vs 3Brython works fine with the older manifest v2 standard. However google deprecated v2. They already stopped allowing extensions using manifest v2 being added to chrome web store, and plan to block manifest v2 extensions from working in a future version of chrome very soon (been delayed a few times but it's coming). Manifest v3 locks extensions down much tighter. v3 requires all extension code to be static, ie only code in (read-only) extension files will run. Chrome doesn't recognize brython code until brython.js translates it to js code. This is forbidden in manifest v3. Using brython with manifest v3 will unfortunately require precompilation to js. I know browser extensions aren't the main purpose of brython. But it's part of the web environment and very useful to have access to (many operations can only be achieved with extension-level access). Bottom lineI understand Pierre's position. I too would prefer to see python scripts natively supported by all browsers. But we don't live in that world yet. Preventing precompilation to js only limits the web platforms that brython can run on. And that limits brython's usefulness and growth. |
I plan to make a tool for that. Had some works these last days, still some stuff to do tomorrow morning, but then I'll try to work on it ;) |
Trying to execute It seems you have a non-UTF8 character in Got also an error :
|
It seems that It seems I'll have to make some adjustment, else I think I can run it in deno. Which will enable me to convert Brython files to JS files from command line. |
Started a project for that : For now the conversion is doing nothing, I have to see how I can execute |
Line 250,
Line 16619 First line should be : var __BRYTHON__= globalThis.__BRYTHON__ ||{} |
@PierreQuentel why do you use an
Can't you replace the Also, "a" isn't defined in |
This error prevents me from going further. @PierreQuentel I'll need your help on this one, I don't know what is this "a" and where it should be defined. |
|
No, it is part of a set of scripts that I developed a few months ago to replace the current parser in You can ignore |
Ok, then I'll have to test again with Shouldn't you remove theses files, or put them in a |
@ed2050 You'll be happy, I'm making good progress on it ;) Got some errors when executing the generated JS, but I'll work on fixing that ;) |
Tested a simple exemple :
Seems to work without But yeah, with small adaptation the AoT seems to be working \o/ |
@ed2050 Brython-AOT is now working ;) I will add several output options one day (an ES6 output could be nice), with or without Python code converted into JS AoT or on-demand, + some ES6 import for top level imports. |
@PierreQuentel I submitted a PR, can you see if you can merge it ? |
Just would like to add some more context to previous comment #2292 (comment) by @ed2050 Although I got Brython-AOT working, and was able to output pre-compiled js, the precompiled file still requires Brython Problem is that brython.js currently does not work for Manifest V3 (mv3) brython.js uses eval or new Function(...), but these are only supported in sandboxed iframes for mv3
If anyone has an idea of how to convert Python code to Javascript for usage in an mv3 extension, please do share ! |
Goals
Perfect integration with existing WebDev tools/pipelines.
Better JS <=> Brython communications through ES6 JS modules.
Enable AOT for Brython.
async imports to anticipate removal of synchronous AJAX due to depreciation.
Step 1: Produce semi-standalone JS
Objective: Make the generated JS less dependant on the Brython module format.
Motivation: A first step that'd enable easier benchmarking as well as easier Brython usage. Would enable to easily create JS files from Brython code.
Validation: Generate code in the Editor and execute it inside JSPerf.
Substeps:
Put the generated JS code inside a
<script type="module">
appened to the<head>
, instead of usingeval()
. Would avoid exposing the current scope, and would authorize top levelawait
andimport
if we wishes to use it.When generating JS code, add a
build_context
parameter, contaning abuild_context.async: [true or false]
option. By default, all python code would be generated with abuild_context.async = true
, but when imported by$B.import()
or$B.import_from()
, the imported module would be built with abuild_context.async = false
.Enable to copy the generated JS into a file we can then import with a
<script src='...'>
tag. For that we need to solve some timing issues. To ensure scripts are executed one at the time, even if some uses top levelawait
, I suggest using a$B.waitMyTurn()
function returning a resolver. Add this to the generated JS code only whenbuild_context.async == true
:To be able to test it, allow users to use the current github dev version inside the Editor. Ideally, select (with a
<select>
) the Brython version he wishes to use. But could be a simple copy/paste of the Editor page, with some modification in order to use the current github dev version. Would enable users to easily test if a bug is still in the dev version (cf recent issues).Optionnally: make a "stable" (3.11), "latest" (3.12), and "testing" (3.12-dev - the Github version) Brython versions in order to avoid unstabilities in production when changing versions (cf recent issues) ?
Step 2 : Async imports
Objective: Enables async import for top level imports in Brython.
Motivation: Synchronous AJAX queries are depreciated.
Note: The strategy is to make the top level import asynchronous. Print a warning for non-top level imports, offering alternatives to users.
Substeps :
When
build_context.async == true
, make the top level dependancies async, by new import functionsawait $B.importAsync()
andawait $B.import_from()
. Then the dependancies (if not already known ofc) would be built withbuild_context.async == true
, and theirwaitMyTurn()
would be immediately resolved (and set tonull
in thewaitingList
- if in it ofc).When still having to use sync AJAX in
$B.import()
, and$B.import_from()
, print a warning "Non top level sync import may not be supported in the future due to the evolution of web standards. Please import this module using a top level import if you want to use it."Step 3: Beta feature: ES6 module format
Objective: Enable easy and "safe" Brython <=> Interactions
Motivation: Enable usage of WebDev tools (bundler, tree shaking, etc.).
Validation: Import a Brython module in ES6 format from a JS code, and import a JS ES6 module from a Brython module.
Note: Would be noted as a "Beta feature", meaning it might not support all of Brython features.
Substeps:
Add support to ES6 JS Module import, replace top level imports by something like:
Add support to ES6 JS Module export. At the end of the generated JS, add several
export ....
to export all top-level symbols (functions, variables). This is equivalant to__all__
in Python. Alternatively, can use a@export
python decorator to indicate the symbols to export/expose in the generated JS module.Step 4: Compatibility with Web Dev tool with 0 adaptation.
Contexte: Let a project with 4 directories :
/libs/Brython (contains current Brython code)
/build/Brython (contains produced ES6 module files)
/src/ (e.g. contains users created python files)
/dist/ (contains the Website that can be distributed)
Objective: Being able to easily build ES6 .mjs files from /src/ to /build/Brython/ which can then be used by existing Web Dev tools like bundlers, tree shaking, etc. For performances, see also HTTP/2 Frequently Asked Questions.
Motivation: Such tools provides a large array of feature we can't expect Brython to implement. It also enables to integrate Web Dev pipeline that would be able to listen to changes into /build/Brython.
Validation: Create a Website with e.g. Webpack and generate a JS bundle.
Note: Would be noted as a "Beta feature", meaning it might not support all of Brython features.
Substeps:
brython-cli build $SRC [$DST]
command to convert a single python file to an ES6 module. In the webpage, could then include a .mjs file instead of a .py file if the user wants to.brython-cli build $DIR [$DST]
, idem, but with a directory. If in a processed file, an imported modules will also have his ES6 JS file, can use normal JS importimport {} from ...
instead of the Brython functions s.a.$B.import_async()
(?). Would facilitate works of JS bundlers tools.brython-cli watch $DIR [$DST]
watch the directory$DIR
and rebuid the .mjs files when its python source file is modified (usingionotify_wait
?).Step 5: Fully standalone ES6 modules
Objective: Integrate current modules and Brython files into the
brython-cli build/watch
process in order to use Web Dev tools/feature on them too (e.g. tree shaking). If we use ES6 modules, would not require to usebrython.js
in the HTML file anymore.Motivation: Would make produce .mjs files fully standalone, and to easily create personnalized JS bundles.
Validation: Create a Website with e.g. Webpack and generate a JS bundle.
Substeps:
import a
brython_runtime.mjs
(subpart ofbrython.js
) at the start of files produced bybrython-cli build/watch
:import __BRYTHON__ from '$BRYTHON_PATH/brython_runtime.mjs'
Could be an alias of
brython.js
in a first time - it doesn't need support to transpile Python code.provides .mjs files for current Brython modules. Thus allowing to reduce the generated bundle to a bare minimum when using AOT Brython.
provides a
brython_eval.mjs
(subpart ofbrython.js
) to support (or not) Python interpretation on the browser (could be an alias of brython.js in a first time). This may bring more security to the Web Page :build_context.aot = [true|false]
. Whenfalse
, do like the current behavior ofmake_dist
, by keeping the Python source (so not transpiled) but make it standalone and expose a ES6 export interface at the end. Relying on existing bundlers to build the final .js file (e.g. Parcel ? or provide a default Webpack config ?) would be great and would reduce the number of tools to maintain.@PierreQuentel What do you think ?
The text was updated successfully, but these errors were encountered: