I am using Angular 5 + Webpack for one of my projects. Now I want to load all assets with JS files (including lazy loaded .chunks.js files) from a CDN.
For CSS and images, I have changed the publicPath option of the webpack so I am able to load CSS and images from the CDN, but the problem is with JS files.
For JS file I have changed the <base href="{{CDN-PATH-HARE}}"> but it gives me this error
I also tried renaming the JS file using webpack but that trick also didn't work.
I just want to know whether I am going in a right direction or I should think it in a different way.
Thanks.
I imagine the "using CDN when performing tree-shaking" discussion could be a fairly involved one...
This answer assumes that the break happens only when switching to the CDN, and that your app is properly served otherwise. Are you sure your app is being served?
The history API is used by angular, but because the origin is different, it's being treated as a security issue.
Assuming external cache-able libraries in a CDN should be included in your bundling, you can try a couple options listed below. I would revisit that assumption first. The point of webpack is to treeshake and then bundle, so I would make sure you are convinced of the benefit of bundling files that are cached and bundled on CDN already.
If you are sure you want to take this approach, you can do a couple things. You can either use hashlocationstrategy on your angular router:
imports [
RouterModule.forRoot(routes, {useHash: true})
]
Or, you can fully host your app when building it, using node's http-server, and play with the host baseUrl in your app's index.html.
Finally, if none of that works for you, you could try using a htaccess file, or doing some manual routing, but I have found those approaches to be a little brittle.
There's a couple pre-existing questions on SO that handle this issue somewhat, but I thought the CDN wrinkle warranted a fresh response.
Angular 5 : Failed to execute 'replaceState' on 'History': A history state object with URL cannot be created in a document with origin 'null'
ng build failed to execute 'replaceState' on 'History': A history state object with URL cannot be created in a document with origin 'null' and URL
How to perform redirects in NodeJS like a .htaccess file?
Maybe a better answer would be to ask this question: If your libraries never change, and you have a version update of your app, why would you force your users to re-download your libraries?
Related
I'm using react +17.0 and the craco (module bundler)
similar to this post,
When I'm trying to preload some images/fonts on my index.html with:
<link rel='preload' as='image' href='assets/images/fooImage.png' crossorigin/>
I've found that preloading does not work because it needs the same image/font name in the assets directory but with code splitting after building I saw that my images and fonts will be renamed in a new name like this:
as a result, preloading still does not work. any help will be appropriate.
What is the problem?
module bundler changes the assets name (adding random numbers to them) on the built version.
so chrome lighthouse (or other performance testers) show that those assets can't find in preload link (index.html) or any related file.
So, What to fix it?
definitely, ejecting or switching to another module bundler like the Webpack and changing the configuration will solve the issue, but I can't do that like many projects.
The standard solution to solve name problem:
transfer all project's assets (static assets) like fonts and images from the frontEnd project (client-side) into a public folder in my server and use its URL in my client-side project.
Now, it can be easily preloaded or anything else.
I'm afraid this will be a stupid question. But I don't manage it to use my JS-Package (for example jQuery), which i have installed with Visual Studio Nuget-Package-Manage in my .net 5 Blazor Server-App.
What i did:
Installing the Package. Here I installed jquery.datatable which includes jQuery itself:
Image of my Project
But now, i don't know how to include it for example in my "_Host.cshmtl"-File:
<script type="text/javascript" charset="utf-8" src="???WHERE IS IT????"></script>
Where is my *.js-File? For example: query.dataTables.js ??
I found it on "C:\Users\xxxxx.nuget\packages\jquery.datatables\1.10.15" and
"C:\Users\xxxxxx.nuget\packages\jquery\1.7.0"
Do i realy have to copy it to my wwwroot-Folder manualy?
If so, why i should use the package-manager?
Thanks for your help!!
Traditional web applications using JavaScript normally load the file from a local folder or from a web CDN (e.g. CDNJS.com etc). This is then loaded from the page (often referenced from a layout file).
Early on it used to be the case that JS libraries could be loaded via NUGET packages but this approach is now discouraged. It had to fix the creation of the script in a set location, e.g. /Scripts and there was no flexibility. Almost all client-side libraries are now in NPM as packages or on CDNs like cdnjs.com.
The current approach for .NET web apps to load client-side assets is either use LibMan or NPM and have some sort of webpack arrangement to compile/pack/copy. You would never load the JS from a /packages folder in the way you suggested.
Blazor Approach
Blazor (since .NET 5.0) can load either embedded JS modules (from your code), or from a URL directly.
If you want to package some JS with your application you should look at Razor Component libraries. This allows static assets such as JS files to be embedded in the code, which Blazor makes available via the _content route, e.g.
_content/LibraryName/myfile.js.
Because Blazor is a SPA you don't include JavaScript using a <script> tag in your HTML, you should load it as a module and reference it there.
This documentation explains it:
https://learn.microsoft.com/en-us/aspnet/core/blazor/call-javascript-from-dotnet?view=aspnetcore-5.0#blazor-javascript-isolation-and-object-references
DataTables, JQuery
So should you include jquery.min.js and jquery.datatables.min.js in your library? I'd suggest a better approach is to load from a CDN - your package is smaller and there is a chance the URL is already cached and loaded, e.g.
var module = await js.InvokeAsync<IJSObjectReference>(
"import", "https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/jquery.dataTables.min.js");
This loads the module on-demand from the URL directly. You'd also need to load jquery before this.
Finally I'd make this observation: are you sure you want to go down this route?
There are several native Blazor libraries on NUGET for rendering and handling tables. You'll find it much easier to go this way rather than try to patch jquery-based libraries into a Blazor app.
I had a similar issue. Not with the same libraries, but I was wanting to do something that wasn't available in a Blazor library yet. I needed a video player that could handle a certain format that the default HTML 5 video element can't handle. There is an open source player, videoJS , that did the job, but it's a javascript library. It's available on npm and there are cdn's - however the plugins (as far as I could tell) weren't on CDN - so I had to go down the npm route.
When you install an npm package it puts it into a hidden node_modules folder. Unfortunately even if you point to that path or even copy the file in with your other js files it won't work. Npm packages are designed to be run by nodejs, rather than directly in the browser. In order for them to run in a Blazor app (in the browser) you have to do an intermediary step of transpiling it into a browser friendly format.
What I really wanted was a re-usable component, that wrapped the javascript.
It took me a while to get there but I finally figured it out. I've written a series of articles on my blog detailing it. The final one ports everything into a Razor Class library that can be consumed with no knowledge of the underlying js. The fourth article deals with importing npm libraries and using them within a web assembly app. I'll put the link below but essentially the process is:
Create a folder eg JS and initialise it for npm (npm init -y)
Install the required npm packages (npm install --save)
Create a src folder within the JS folder that that you will put your own js files in
Create an index.js file in src that imports the required javascript modules and exports what you want to consume
Install snowpack (npm install snowpack --save-dev) (or webpack but I found snowpack seems to work better)
Configure snowpack to process the contents of the src folder into wwwroot/js (without snowpack or similar the files in the npm package won't be in a browser or blazor useable format)
use javascript isolation to pick up your index.js file from wwwroot/js
See blog post here for full details (It's part 4 of a 5 part series - part five puts it all in a razor class library so you can add it to a project without ever seeing the javascript)
I know this is late but this SO question was one I kept coming across when searching on how to do what I wanted, so thought I'd put my solution here in case it helps anyone else searching for what I did.
When I use the gulp-sourcemaps plugin, I typically have both the comment and content removed so the sourcemap header is used instead. This makes it much easier to show the original files in the browser debugger in development and staging, then remove it in production. We also try to load sourcemaps wherever possible, mostly for vendor libraries.
This works fine for the most part. However, intermediate files seem to be lost. I am guessing the loadMaps option to sourcemaps.init(), which allows for loading existing maps, removes the intermediate files when it gets their maps. This is likely fine for most cases, as the original files are there, but too often libraries only include the output file with maps added as a comment, but don't include those original files. This means we don't have access to the original files, and the browser does not have access to the built library file.
For example, angular-ui-router is written with TypeScript, then output to JavaScript when built. This means the end developer does not have to compile with TypeScript in his/her build process, as this is already done in the ui-router build process. Now, the output JavaScript file is accessible at <server root>/node_modules/#uirouter/angularjs/release/angular-ui-router.js, and the original TypeScript files were, according to the built file's sourcemap comment, in the <server root>/node_modules/#uirouter/angularjs/node_modules/#uirouter/core/src and <server root>node_modules/#uirouter/angularjs/src folders.
When I include the angular-ui-router file into a vendor.js or vendor.min.js file using my favorite tool, it bundles the angular-ui-router maps into the resulting .map file, but does not include the <server root>/node_modules/#uirouter/angularjs/release/angular-ui-router.js file as a source. This means we can't see either that file, or the TypeScript files, which makes debugging pretty much impossible using only the browser. To make matters worse, any errors we get are sourcemapped all the way back to the TypeScript files. We don't have the TypeScript files, so we can't look there, and now we don't know where in the JavaScript the error is, either! Thankfully, angular-ui-router doesn't have many complex errors, and the ones it does have are nicely documented, but other libraries are not so helpful.
Is there a way to include intermediate files as sources in the output sourcemap? Otherwise, is there an easy way to load some sourcemaps with something like loadMaps, but not others?
So I'm trying to extract my own CSS framework from my projects so I can develop it separately.
I have my index.html with less.js and included my main .less file which #imports a dozen other files...
However, in the console I get an error for each of my less files:
Resource interpreted as Stylesheet but transferred with MIME type text/plain: "file:///path/to/project/src/file.less".
And a final line that says Less has finished and no sheets were loaded.
So I understand this to mean they aren't being served correctly, I normally use Node.js/Express, but I don't want to include all of that in my repo just to develop some CSS. How do I get around this?
I thought about using some node package like serve for development but I feel like this shouldn't be necessary.. Unless I'm wrong?
EDIT: here's my repo, https://github.com/kenmorechalfant/framewerk
Don't use file://. You're going to run into a mountain of XSS errors. Just use a quick static HTTP server. I use http-server with node and most IDEs have one built in. It is going to be more trouble that it's worth to try and not use a static HTTP server if you don't have a good reason not to.
I have deployed a Laravel 5.3 application to Heroku. However, when loading /login, I noticed a very slow page load time. The problem seems to be a very large app.js file: /js/app.js. Here is a screenshot of the Network resource panel in DevTools: screenshot- Network panel. The 3rd resource from the top is the offending file.
I am not sure why this file has gotten so large. here is a link to the repository: https://github.com/AshMenhennett/Salon-Pricing.
I wasn't able to post anymore links, so do let me know if you would like direct links to specific files.
What should I be doing to mitigate this issue?
The most obvious thing you can do is to run npm run prod. This will compile the assets for production use. But in most cases, you must be looking at other solutions beyond running npm run prod. If your production file is too large, you must check your dependencies. Remove unnecessary dependencies and ensure that you don't use a lot of external libraries. For example, if you are using bootstrap, you should rely on Bootstrap's alerts in order to show alerts rather than using a Vue package to show alerts. I admit that sometimes you will need to use an external library to make your website interactive but to achieve that, you will have to sacrifice the performance. So your best bet in order to reduce the app.js file is to use the minimal external dependencies in your package.json.
The second thing you can do is use minimum HTML in your components' templates. A lot of components with heavy HTML/CSS will contribute to a larger app.js file. This is yet another approach that will result in a smaller app.js file.
Lastly, you should consider using Vue's component slots to pass HTML contents to your components. This will leave the HTML in your static files and only javascript data (API calls, props, etc.) will be compiled in the app.js file. This is an effective approach to build a smaller app.js file.
Edit: You can remove JQuery and Bootstrap scripts from the bootstrap.js file and can include these dependencies separately. It is always a good idea to have a few more scripts rather than having a very large script. i.e. browsers do parallel downloading and thus using JQuery and Bootstrap dependencies separately is a good idea.
From the looks of your link you've not created a production version of your assets, and currently all the source maps are in your app.js file, which will be adding a lot of the file size, the css and js output are also not compress/minified either.
Assuming you're using laravel elixir, you just need to run gulp --production and this will remove the source maps, compress the js and css outputs, etc.
For people that are using Laravel Mix you just need to run npm run prod to compress and remove source maps from app.js itself.
You need to load the components asynchronously
Webpack has an awesome feature to create chunks of code. The key to this is to use async components. These components get loaded completely asynchronously whenever the component is present on the page you just loaded.
Let's do it.
In resources/js/app.js
I changed
Vue.component('jobs', require('./pages/employer/jobs/Index.vue').default);
To
Vue.component('jobs', () => import('./pages/employer/jobs/Index.vue'));
and in webpack.mix.js
mix.webpackConfig({
output:{
chunkFilename:'js/vuejs_code_split/[name].js',
}
});
Now by running npm run watch or prod each component file is saved public/js/vuejs_code_split/[name].js
And the main app.js is automatically calling those components when required.