Importing Specific Package Files
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeSometimes, instead of importing a package itself, you may want to import only part of it: like a specific file. Lodash is a good example of this.
No Tree Shaking in the Browser
But before we get there, instead of importing everything from lodash, you should be able to say import { camelCase } from 'lodash'. Then, down here, you would use camelCase directly.
| // ... line 1 | |
| import { camelCase } from 'lodash'; | |
| // ... lines 3 - 4 | |
| console.log(camelCase(mix.describe())); |
However, when we move over and try this... error!
The requested module
lodashdoes not provide an export namedcamelCase.
This should work... and the reason it doesn't is complicated. Basically, due to the way that this specific library packages their module, you can't import specific functions like this. It will work with most other packages, however.
For example, if you say import { Modal } from 'bootstrap' (if you're using Bootstrap), that will work. Bootstrap packages their files correctly.
However, using this syntax may not always be ideal with AssetMapper.
Here's the problem. If we ran this code through Encore, Encore would do something called "tree shaking". This is where it would see that we're only importing camelCase from lodash. And so, in the final JavaScript, it would only give us the code for camelCase, not the entire lodash package.
In a browser environment, if you import from lodash, you're going to get all of lodash... even if you're only importing one part of it. Now, that might not be that big of a deal. The full build of lodash is still only 24 kilobytes. But what if we are using a big package... but only need to import one specific thing?
Importing a Specific File
A lot of times, there's a specific file that we can import, like /camelCase. You'll usually find details about these files in the docs... though you can also go look for them. Head back to JSDelivr... and down here, search for "lodash". Below, click "Files" to see all the files that are part of this package.
For lodash, it's a huge list... because this is a huge library. One of these is camelCase.js.
Ok! So let's try importing lodash/camelCase.
| // ... line 1 | |
| import camelCase from 'lodash/camelCase'; | |
| // ... lines 3 - 6 |
I'm not including the .js... but it's not going to work anyway. Watch: when we refresh... error!
Failed to resolve module specifier
lodash/camelCase. Relative references must start with either "/", "./", or "../"
This error means that we're importing something using a "bare" import, and it was not found in the importmap. If we "View Page Source", we do have an importmap for lodash, but not lodash/camelCase. Yup, that matching is done exactly. Ok, there is a way to do a, sort of, "fuzzy" matching - lodash/* - but I don't use that.
The point is: if you want to use lodash/camelCase, you should add that to your importmap, not lodash.
Watch: find your terminal and run:
php bin/console importmap:remove lodash
That will remove lodash from importmap.php and delete the file from assets/vendor/.
| // ... lines 1 - 15 | |
| return [ | |
| 'app' => [ | |
| 'path' => 'app.js', | |
| 'preload' => true, | |
| ], | |
| ]; |
Nice! Now run ./bin/console importmap:require with the package name / the path that you want: lodash/camelCase.js.
php bin/console importmap:require lodash/camelCase.js
camelCase.js is the name of the file over on the CDN. But you'll notice that, a lot of times in the docs, they'll reference lodash/camelCase without the .js. And in this case, you can leave the .js off: it's up to you. That works because jsDelivr is friendly and makes both versions of the URL work.
The result of the command? The same as before! We get a new entry in importmap.php matching what we want to import and set to a URL.
| // ... lines 1 - 15 | |
| return [ | |
| // ... lines 17 - 20 | |
| 'lodash/camelCase' => [ | |
| 'url' => 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/camelCase/+esm', | |
| ], | |
| ]; |
Copy that URL so we can see it. There we go! It's the code from just camelCase.js.
And when we try the page... it works!
Here's the takeaway: if you need to import a specific file from a package, you can do that: just pass the package name + file path to importmap:require.
Next, let's add Stimulus to our app!
8 Comments
Hi,
I have trouble getting run a specific library. It is vis-timeline that can be accessed via jsdelivr.com.
Here is what I did:
First I installed vis-timeline via
php/bin importmap:require vis-timelinewhich gives me 3 items:So that seemed to be successful.
Now I want to use the libraries in one of my stimulus controllers:
However I run into errors:
So whats missing or what do I wrong?
Thanks for any help here.
Oliver
Hey Oliiver,
I personally haven't used this library, can't say much about it. But it seems like you're trying to import it incorrectly. Maybe try this way:
I wonder if it works this way, though it's mentioned as a legacy way, so probably there should be a better way. I also see it's imported as
vis-data/peerso probably you should import it that Peer way? See the docs: https://github.com/visjs/vis-timeline?tab=readme-ov-file#peer-buildI hope that helps!
Cheers!
Hi Victor,
thanks for your reply.
I figured out what the problem was. First I wondered why vis-data throwed the error but not vis-timeline. I removed all references to vis-data and then the error was gone. So I assumed that vis-timeline was importing correctly.
Then I checked importmap again and saw something interesting.
I used only one importmap:require vis-timeline, which imported three things:
In importmap I saw the following
So with that I concluded that I need to import 'vis-data/peer/esm/vis-data.js' and not something else.
And "tada" the error was gone.
I am not at the end. There is a subsequent error I need to take care of, but the initial error is gone, which seems, that the libs are loaded correctly.
Thank you
Oliver.
PS:
I might come back, if I need help with the next error.
Latest update:
remove all vis-timeline related libs
add vis-timeline/standalone
Use the following imports:
And thanks for sharing the final solution with others!
Cheers!
Hey Oliver,
Good thinking! I'm glad you were able to fix that, indeed it makes sense to include that path that exists after you install the package, good job!
Cheers!
i have a big Problem: how to install opencv.js ? thats not possible at my projects
hey @timm
What about
php bin/console importmap:require opencv.js? Does it work?Cheers!
"Houston: no signs of life"
Start the conversation!