We're beginning work on a couple of fully JavaScript-dependent web apps (our previous apps have been ASP.NET MVC, with JavaScript 'goodness' sprinkled over-the-top).
We have a few files that will be shared across the board, and it would be nice to store these files in a Common project, and 'Add As Link' them into individual projects (as would be possible with compiled code).
Obviously this doesn't work with something like JavaScript as the file isn't actually 'there' in the correct location.
Does anyone have any suggestions on keeping a single version of a shared JavaScript file, for use across multiple projects?
I know this issue is ancient, but still wanted to put forward my solution because it is a bit simpler than beardtwizzle's.
You can ensure that Visual Studio copies all linked files to where you placed the link in Visual Studio's Solution Explorer by adding this at the end of your .csproj file:
<Target Name="CopyLinkedContentFiles" BeforeTargets="Build">
<Copy SourceFiles="%(Content.Identity)"
DestinationFiles="%(Content.Link)"
SkipUnchangedFiles='true'
OverwriteReadOnlyFiles='true'
Condition="'%(Content.Link)' != ''" />
</Target>
I've described how this works in my blog post at
http://mattperdeck.com/post/Copying-linked-content-files-at-each-build-using-MSBuild.aspx
In the end, this is how I've achieved it. It may not be to everyone's taste - but worked a treat for me.
Note: In all of our projects, static resources are in a root directory called 'Assets', so for example JavaScript is always in /Assets/js/ and CSS /Assets/css/.
Solution
In the project that is going to 'import' the common code, I simply add the common .js file 'As Link' within /Assets/js/.
Go to that new addition's Properties and set 'Copy to Output Directory' to 'Copy if newer'.
Now I simply edit the project's post-build event command line to the following:
xcopy /Y /E "$(TargetDir)\Assets" "$(ProjectDir)\Assets"
When the project builds, it copies the imported files to \bin\Assets\js - the post-build event then takes a copy of those over to the project directory - in time for the site to use them.
The correct solution is embedding javascript/css files in your project. You can do this by using WebResources.axd. This is the official way microsoft embeds js in its controls. (Like validation controls)
You can find a good tutorial on: https://web.archive.org/web/20211020131200/https://www.4guysfromrolla.com/articles/080906-1.aspx
I can also see this question is ancient, but thought I would add my two cents...
I have a javascript file in a separate project. I added a linked reference and this works well for publishing, but doesn't work in IIS Express or Casinni. I tried adding custom routing to catch the missing file and manually remap it, but it is bit of a hack and for some reason stopped working when I upgraded to MVC 5.1, so rather than fix the hack, I found a better way:
System.Web.Optimization has javascript bundles.
In your shared project, set the Copy To Output Directory to 'Copy Always' and Build Action to 'Content' on your js file. This means your js files end up in the bin folder of your website project. They cannot be served from there (IIS wont serve anything in the bin folder for obvious security reasons), but they can be included in bundles
using System.Web;
using System.Web.Optimization;
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/externalLibrary").Include(
"~/bin/scripts/externalLibrary.js"
));
}
}
You then need to add this to Application_Start in your global.asax file (right next to register routes)
BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
then use your bundle link this in your razor cshtml:
<script type='text/javascript' src='#System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/bundles/externalLibrary")'></script>
you will need the nuget package for microsoft.aspnet.web.optimization
Anyone that stumbles across this question here in the future should know that there are now Shared Projects in Visual Studio to solve this problem. Universal Windows projects use them by default and you can create your own by downloading and installing the VS extension here: https://visualstudiogallery.msdn.microsoft.com/315c13a7-2787-4f57-bdf7-adae6ed54450
Once you download the extension you can add a Shared Project (Empty) to your solution. The project can be found in the project templates for Visual C#, Visual C++, and JavaScript.
Then include the files you want to share to the shared project in any folder structure that makes sense for you.
Next you will include the shared project as a shared reference in the other projects in that solution that need access to the shared files. Right-click the other project and choose "Add Shared Project Reference".
Now you can reference the shared files in your main project as if the files in the shared project existed there. They are compiled as part of that project.
The technology was intended for Universal apps to share code between Windows Phone and Windows Store apps so be warned that you may have trouble sharing in different scenarios but it is worth a try to see if it will fill your need.
You could perhaps use visual studio templates
great question, I've been thinking about this for quite some time. The only solutions that have popped up in my mind are hosting the files on the web and using them like a cdn or using symlinks. You could add a code snippet into your visual studio to reference them.
This blog post describes an alternative solution to the answer by #beardtwizzle:
http://consultingblogs.emc.com/jamesdawson/archive/2008/06/03/using-linked-files-with-web-application-projects.aspx
The idea is similar:
Add the shared file to to web project as a link
Modify the _CopyWebApplication build step in the project, so that the linked files are copied correct destination path.
So instead of a post build event the files are copied by a modified build step. For me this solution feels a little bit cleaner (but this may well be a matter of taste). Anyway I just added this to our solution and it works great so far!
Use proper version control.
Keep the js in one location and then just git pull (or the equivelant Mercurial / Bazaar) them back into your code whenever you've updated your javascript.
Related
In case the question wasn't clear. I have 3 MVC projects in one Solution. Every time I create a new project it adds the "Scripts" folder with all the .js files I'll ever need. I don't want to have this created every time for every application. Is there a way to reference scripts from a central folder in the solution so all applications/projects can share one common script folder with all the scripts common among them?
Edit:
Please explain the pros and cons of doing this if there are any...now I'm curious.
Here is what I would recommend:
Right click the solution and create a New Solution Folder called Common Javascript Files (or whatever you feel like calling it.
Right click on the Solution, click Open Folder in Windows Explorer,
or navigate there manually for other versions of Visual Studio :(
In the solution directory, create a directory with the same name as the solution folder (solution folders do not normally match directories at the source code level but this will for sanity sake).
In this new directory, add files that need to be shared between solutions.
In Visual Studio, click the solution folder and select Add - Existing Item.
In the file selection dialog, navigate to the directory previous created, select the file(s) added to the directory and click Add.
In each Project that needs a shared file, right click on the project (or directory within the project) and click Add - Existing Item.
Navigate to the shared Directory, Select the files and click the drop down arrow then click Add As Link.
Now the files in the projects are essentially short cuts to the files in the Solution Folder. But they are treated as actual files in the project (this includes .CS or Visual Basic files, they will be compiled as files that actually exist in the project).
PROS
Files are truly shared across projects at Design time
Only the files needed for each project can be added, it's not all or nothing
Does not require any configuration in IIS (virtual directory etc)
If the solution is in TFS Source control, you can add the Directory to the TFS Source and the shared files will be source controlled.
Editing a file by selecting it in the Project, will edit the actual file.
Deleting a Linked file does not delete the file.
This is not limited to JS files, linked files can be ANY file you might need (Images, Css, Xml, CS, CSHTML, etc)
CONS
Each deployment gets it's own file.
There is a small learning curve when understanding that Solution Folders are not Directories that exist in a Solution Directory.
The best thing to do, imo, is to roll your own CDN... Basically just create another site in IIS and give it it's own binding, e.g. "http://cdn.somedomain.com"
Then store all of your css/js/fonts/shared images etc on the CDN site and link to them from your other sites.
Doing so solves 2 problems,
All of your stuff is shared when it needs to be and you only have to manage 1 revision per file.
Your users browsers can cache them in 1 single location instead of downloading copies of your stuff for every site that uses them..
I added this answer because I see a lot of people referrencing creating virtual directories. While that does indeed share the files, it creates multiple download paths for them which is an extreme waste of bandwidth. Why make your users download jquery.js (1 * number of sites) when you can allow them to download it once on (cdn.somedomain.com).
Also when I say waste of bandwidth, I'm not just talking about server bandwidth, I'm talking about mobile users on data plans... As an example, I hit our companies HR site (insuance etc) on my phone the other day and it consumed 25mb right out the gate, downloaded jquery and a bunch of stuff 5 times each... On a 2gb a month data plan, websites that do that really annoy me.
Here it goes, IMO the best and easiest solution, I spent a week trying to find best and easiest way which always had more cons than pros:
Resources(DLL)
Shared
images
image.png
css
shared.css
scripts
jquery.js
MvcApp1
Images
Content
Shared <- We want to get files from above dll here
...
MvcApp2
Images
Content
Shared <- We want to get files from above dll here
...
Add following to MvcApp1 -> Project -> MvcApp1 Properties -> Build events -> post build event:
start xcopy "$(SolutionDir)Resources\Shared\*" "$(SolutionDir)MvcApp1\Shared" /r /s /i /y
Here is explanation on what it does: Including Build action content files directory from referenced assembly at same level as bin directory
Do the same for MvcApp2. Now after every build fresh static files will be copied to your app and you can access files like "~/Shared/css/site.css"
If you want you can adjust the above command to copy scripts from .dll to scripts folder of every app, that way you could move some scripts to .dll without having to change any paths,here is example:
If you want to copy only scripts from Resources/Shared/scripts into MvcApp1/scripts after each build:
start xcopy "$(SolutionDir)Resources\Shared\Scripts\*" "$(SolutionDir)MvcApp1\Scripts" /r /s /i /y
This is a late answer but Microsoft has added a project type called Shared Project starting Visual Studio 2013 Update 2 that can do exactly what you wan't without having to link files.
The shared project reference shows up under the References node in the
Solution Explorer, but the code and assets in the shared project are
treated as if they were files linked into the main project.
"In previous versions of Visual Studio, you could share source code between projects by Add -> Existing Item and then choosing to Link. But this was kind of clunky and each separate source file had to be selected individually. With the move to supporting multiple disparate platforms (iOS, Android, etc), they decided to make it easier to share source between projects by adding the concept of Shared Projects."
https://blogs.msdn.microsoft.com/somasegar/2014/04/02/visual-studio-2013-update-2-rc-windows-phone-8-1-tools-shared-projects-and-universal-windows-apps/
Info from this thread:
What is the difference between a Shared Project and a Class Library in Visual Studio 2015?
https://stackoverflow.com/a/30638495/3850405
A suggestion that will allow you to debug your scripts without re-compiling the project:
Pick one "master" project (which you will use for debugging) and add the physical files to it
Use "Add As Link" feature as described in Eric's answer to add the script files to the other projects in solution
Use CopyLinkedContentFiles task on Build, as suggested in Mac's comment to copy the files over to the second over to your additional projects
This way you can modify the scripts in the "master" project without restarting the debugger, which to me makes the world of difference.
In IIS create a virtual folder pointing to the same scripts folder for each of the 3 applications. Then you'll only need to keep them in a single application. There are other alternatives, but it really depends on how your applications are structured.
Edit
A scarier idea is to use Areas. In a common area have a scripts directory with the scripts set to be compiled. Then serve them up yourself by getting them out of the dll. This might be a good idea if you foresee the common Area having more functionality later.
Most of the files that are included by default are also available via various CDN's.
If you're not adding your own custom scripts, you may not even need a scripts directory.
Microsoft's CDN for scripts: http://www.asp.net/ajaxlibrary/cdn.ashx
Got a few issues setting up a project to do the full Java, Angular.js, TDD/BDD stack. So far these issues aren't a blocker, but they might turn into one.
I'm using Eclipse 4.6.0 Neon with the WTP, JSDT and Angular plugins.
The 2 red flags that I see waving at the moment are:
in the "Javascript Resources" folder, Eclipse is showing an "ECMA 3 browser support library". This should be ECMAscript 5 surely? (If not 6!) Since Neon just came out, it's a bit of surprise that I can't even change it as I can change the Java version for instance in the project facets dialog.
the HTML and CSS files are buried in src/main/webapp. I shouldn't have to do 3 clicks to get to them, they should be as easy to click to as the Java or JS files. How come there's no "Web Resources" to match the "Java Resources" and "Javascript Resources" in my project in the Project Explorer view?
Like I said at this point neither of these /seem/ to matter but I'd hate to waste loads of time on a problem in the future and find out I should have set up my project differently. I'm also quite happy to hear that this is impossible and I should split the technologies out into separate projects, like one for just web services and one for JS. To follow that train of thought to its conclusion, I'm also happy to hear that I should ditch Eclipse and go back to the command line.
Update 2016-08-01
The Eclipse project went into a nose-dive, locked into some never-ending process which I couldn't stop and couldn't identify after I created a bower.json project file.
I will separate the Java and JS into separate projects and take it from there. There is no need to keep them together except the benefit of having only one deployable artifact not 2, and right now that doesn't seem like such a big deal.
Answer for 2nd item [src/main/webapp requiring 3 clicks to drill down into (unlike the Java files)]:
You should be able to right-click on the /webapp/ folder, then select "Build Path" > "Use as Source Folder", and it will then be displayed at the same level as the Java (src/main/java) folder is, enabling you to drill into it with one click.
Here is how it looks in Eclipse's 'Package Explorer':
I found it easier to set up the Javascript / Angular.js, HTML and CSS in a separate project in Eclipse because the Eclipse project config probably went up the creek as I continually bashed away at it.
This means there have to be 2 deployable artifacts but at this point that's acceptable. When it comes to production and definitely if it becomes easier as the Eclipse JS tooling matures, I will recombine then into one project.
All the google top-ranking JS / Angular HOWTOs out there on the net assume no java or maven at all will come into it, but I have a variety of use-cases where I want the HTML in JSP files rather than as static files, so I created a project as Javascript, Java and Maven.
Also, there is an awesome looking Maven plugin frontend-maven-plugin
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.0</version>
</plugin>
which is, quote:
Maven-node-grunt-gulp-npm-node-plugin to end all maven-node-grunt-gulp-npm-plugins.
So this will take care of the continuous integration of browserify and grunt or gulp tasks.
It's easy to split out the HTML and CSS resources and put them into the WebContent directory that is automatically created for an Eclipse Dynamic Web Module. That makes them reachable with one click of the mouse in the folder tree (compared to 3 clicks in src/main/webapp).
In fact using the maven-war-plugin it is simple enough to tell Eclipse where to assemble the various parts from:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warSourceDirectory>${project.basedir}/WebContent</warSourceDirectory>
<webResources>
<webResource>
<directory>${project.basedir}/src/main/javascript</directory>
</webResource>
</webResources>
</configuration>
</plugin>
To bring in ECMAScript 5 or 6 support, I installed the Tern Eclipse plugin which doesn't quite take over the project configuration since Eclipse still shows the ECMA 3 Browser library in its properties dialog, but it provides code completion and validation.
Apparently this whole thing is easier with IntelliJ but hopefully this was the last big session on the Eclipse project config that I'll need to do for a while, so I won't be going there just yet. No idea about Netbeans.
Update 2016-09-23:
The Eclipse project configuration isn't very stable. At first the Angular plugin couldn't find my Angular code and flagged up errors in the HTML unless the Javascript is in the same directory or subdirectory where the HTML is. I discovered that these errors just disappeared after I recreated the Eclipse project from scratch.
The default validations carried out by Eclipse are also not good. They check everything in node_modules and bower_components unless turned off or reconfigured with a filter to exclude those directories (there are over 25 separate validation configurations to do).
Also, the Javascript outline view breaks when it tries to scan in the code in 3rd party libraries like angular.min.js or d3.min.js - there is a release 4.6.1 due at the end of September this year 2016 with a fix for this.
/
..Common/Scripts/Script1.js
..Sharepoint2010/Layout/Scripts/[reference to Script1.js]
..Sharepoint2013/Layout/Scripts/[reference to Script1.js]
Developement for Sharepoint allows to deploy resources such as js and css files.
Different versions of Sharepoint have different metadata (project types, webparts, paths), but the source js/css are the same.
Programmatically it's best to have a signle copy of resource and use it from these different projects.
So editing Script1 in Sharepoint2010 project and saving it eventually result in updated Common/Script1.js which will be i.e. updated automatically for Sharepoint2013.
I'm relatively new to sharepoint, but I'm not searching for "use build options, cmd xcopy /sp2010/script1.js common/scripts/script1.js".
I'm using WebEssentials to simplify development, there are bundles, which defines path to resources and then compile these resources, but that doesn't work with the given scheme.
If I understood your problem correctly, "Add as link" option in Visual Studio can help you. The article is actually about Win8 development, but whatever.
I'm stuck... I'm trying to reference a javascript file that has been embedded inside a third party assembly, but it doesn't seem to work:
What I've done:
I have a folder RefAssemblies where this library DLL with embedded javascript file is located
I added a project reference and pointed to this library assembly
I added a line in my javascript file where I want the reference to work ie.
/// <reference name="ScriptName.js" assembly="AssemblyName" />
I tried naming my assembly with name only, and also with full assembly name including name, version, culture and public key token. No difference.
Added my library assembly to my project's web.config inside system.web\assemblies (AFAIK that's the part where you have to add your assembly and make it well-known in your application) so I should be able to access it without referencing assembly at all just resource name. No difference.
And yes I was pressing the Ctrl+Shift+J after any change I've done so Visual studio refreshed Javascript intellisense cache. I even unloaded and reloaded my web project after I changed web project's web.config. Just so that Visual Studio would read the file and reload everything anew.
But still unlucky... And I'm not getting any Javascript Intellisense errors in the General output window either...
I must be missing something...
Additional note:
It may be helpful to know that I'm running ReSharper 6.1.1000.82 within Visual Studio 10.0.40219.1
Other things I've done afterwards
Uninstalled ReSharper from my machine
Reset Visual Studio by running it from command prompt using
devenv /ResetSettings
No luck either.
Do you have any other suggestions I might do?
I'm also having odd problems with embedded resources. I have managed to get it working though by using the fully qualified resource name. You can find that out by using ilspy to open the assembly and then select the Resources folder, then the full name of all the resources will be displayed.
As i said i have gotten this to work in one solution, but in others it doesnt work and i have no idea why.. the non working solution has a diffrent structure where the diffrent assemblies are in diffrent folders, but i have nto been able to isolate that as the cause..
-edit-
After much trial and error it seems like the key thing to making embedded javascript references work is to set the output folder for the project containing the reference to bin and not bin\debug.
from what i can gather, there are no other settings or assembly references that affect the embedded resources, only the output folder of the project that has the reference. i'm guessing that the javascript language service is unable to find the assemblies with embedded resources unless they are in the private path or the gac, but i have yet do understand exactly where this binpath is set.
i've tried setting it on the project itself and on what i think is the actual language service exe, but to no avail.
i made a connect issue here:
https://connect.microsoft.com/VisualStudio/feedback/details/770185/js-references-to-embedded-files-require-the-referencing-project-to-have-outputpath-bin
I work on front end development and am looking to find a solution for working with javaScript between (non compressed and multiple files) development environment and (compressed and combined files) live environment.
I have found a solution with CSS which means that I only need to include one global CSS file with imports, then we combine and compress those imports when deploying to a live environment. This means that we don't have to toggle adding references in to the head for dev and live.
Any ideas on a similar solution for JavaScipt?
Thanks
Dave
If you are using jQuery it's really easy to include external Javascript files from within Javascript which is basically what you described you did with CSS.
Read up on jQuery getScript()
You can use Charles Web debugging proxy. Or smth similar.
Charles allows to give any local file instead of any url. So you can give your browser your local JS file instead of live JS. Thus you will be able to test JS or CSS changes without showing them to your users.
I use ESC to merge and compress all the independant JavaScripts to a central one, and have it run as a 'post build' task.
For Visual Studio I wrote a small console application I wrote (like ESC as someone mentioned) that is used as a post-build event. It's simple but automates the job you're describing by:
Taking a list of filenames as its arguments
Compressing each one using Crockford's JS compressor
Combining the output into one .js file
Then in the site project, the file is loaded from a resource, and a toggle is performed in a class
List<string> files = new List<string>();
#if DEBUG
files.Add("MyNamespace.Javascript.script1.js");
files.Add("MyNamespace.Javascript.script2.js");
#else
files.Add("MyNamespace.Javascript.Live.js"); // single file
#endif
// ScriptManager.Register them
You could also enable GZIP compression on the JS files for even faster load times. If you're not using the Microsoft dev environment then I'll delete this.
Thanks for all your responses. I have come up with a solution which uses some of your ideas.
i have a global js file which has a list of files to include and when run during dev just writes the script links to the page.
Then included in the deployment process is a script which parses the global js file, looks up which files it is linking together, combines and compresses them in to one global js file.
This means that I don't need any server side code during the process which makes things easier to maintain across a team of freelance front end devs.
i'll post the final bunch of code when it's ready on my blog.
I don't know how your dev environment looks like but you could put all the script tags into one file for development and have another for production that has the script tag for your one single file. For example: development_js.extension and production_js.extension.
Then it's just a matter of either using server-side include or some build tool to merge the correct file into your HTML file.