ES6 does provide modules; but unless you’re using Babel you’ll have to rely on third-party libraries such as RequireJS until all major browsers support them.
How simple a modules implementation could possibly be? It should at least be
able to register modules and require a module inside another; much like
import. It should also handle issues like circular dependencies
bar which requires
foo) and undeclared modules.
Modules should be lazily loaded, i.e. only when they are required; and
requiring twice the same module shouldn’t execute it twice.
Well, here is one:
It’s 136-bytes long. 139 if you count the variable definition. At this level you can’t expect long function names but here is an usage example:
This code will print
42 in the console. It only uses two modules but the
implementation works with an arbitrary number of modules. A module can depend
on any number of other modules that can be declared in an arbitrary order.
Consider this example:
m1 depends on
m2 which depends on
m3 which itself depends on
implementation won’t die in an endless loop leading to a stack overflow but
will fail as soon as it detects the loop:
Admittedly this error message doesn’t give us too information but we have to be
thrifty in order to fit under 140 characters. The prefix
p: tells you the
error comes from
p, and the part after is the faulty module. It can either be
a wrong name (the module doesn’t exist) or a circular dependency.
Note: don’t use this at home. This is just an experiment; I eventually used Browserify for my project.
We need an object to map modules to their functions; we’ll populate it on calls
register. We need another object to store the result of their function
call; i.e. what they export. I added a third object to “lock” a module while
it’s executed in order to detect circular dependencies.
We’ll have something like that:
This works and is pretty short; but that won’t fit in a Tweet ;)
Let’s compact the exceptions into one because those strings take a lot of place:
The error is less explicit but we’ll accept that here.
We try to get as little code as possible then use YUI Compressor to remove the spaces and rename the variables. This means we can still work with (mostly) readable code and let YUI Compressor do the rest for us.
I measure the final code size with the following command:
Right now we have 240 bytes. We need a way to remove 100 bytes. Let’s rename
the public methods are reduced to their first letter. We can also remove the
p will be global anyway. Let’s also reduce the error message
That’s 186 bytes once compressed. Not bad! Note that we have twice the same
line in the
g function (previously known as “
We can invert the first
if condition and fit the whole code in it;
returns into one. This is equivalent to transforming this
Into this one:
The first form is preferable because it removes one indentation level for the
function body. But here
return is a keyword we can’t compress.
Speaking of keyword we can’t compress; how could we remove the
delete? All we
care about is to know if there’s a lock or not, so we can set the value to
false instead, at the expense of more memory. This saves us only one byte but
since we only care about the boolean values we can replace
We’re now at 166 bytes and the
g function looks like this:
Now, what if we tried to remove one of the three objects we’re using? We need to keep the functions and the results in separate objects but we might be able to remove the locks object without losing the functionality.
Assuming that modules only return objects let’s merge
l. We’ll set
0 if it’s locked and will then override the lock with the result.
p.m[A] then have the following possible values:
undefined: the key doesn’t exist; the module hasn’t been required yet
0: the module is currently being executed
- something else: the module has already been executed; we have its return value
We need to modify our code a little bit for this:
Note that this allowed us to get ride of the
finally which let us go
down to 143 bytes. We can already save two bytes by using
< 1 instead of
OR) saves one more byte and
allows us to fit in 140 bytes! We can go further and remove the brackets for
if since it only has one instruction. We need to do that after the
compression because YUI Compressor adds brackets if they’re missing.
The final code looks like this:
That’s 139 bytes once compressed! You can see the result at the top of this
Please add a comment below if you think of any way to reduce this further while preserving all existing features.
Thank you for reading!