Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
abraham linksys
Sep 6, 2010

:darksouls:
This is a thread about modern front-end web development frameworks, tooling, and practices.

What is modern front-end development?

A long time ago (in client-side terms), John Resig released jQuery, drastically simplifying life for developers doing client-side scripting. Abstracted away were awkward APIs like XMLHTTPRequest or the seventeen different implementations of the DOM, replaced by cute little $("selectors") and $.get("/my-rad-resource"). Of course, jQuery wasn't the only library attempting to simplify front-end development: new frameworks like Dojo, YUI, and SproutCore were being released around the same time, attempting to simplify a minefield of half-implemented specs and poorly-understood standards.

Life was good. jQuery became a de facto standard over time, people shared plugins that made it (relatively) easy to drop in widgets and custom behavior, and code became cleaner and easier.

But there were problems on the horizon. Client-side code became larger as the client became more capabilities, with no clear way of organization. It was hard to write anything with actual dependencies. It was even harder to write custom build steps to concatenate and minify your code in production, so the browser wouldn't have to deal with a meg of JavaScript split across 200 <script> tags.

Thus, developers started making cool things to make it easier to develop apps, and that's led to the modern front-end development scene today.

Frameworks
Tooling


This post used to have sections on these, but they became comically out of date literally like two months after I posted them, because of course they did it's JavaScript. Maybe some day I'll update them! Until then, try the tried and true method of picking a framework and build system based on the most Hacker News posts about it, or possibly where it ranks on Google Trends.

abraham linksys fucked around with this message at 20:09 on Apr 5, 2015

Adbot
ADBOT LOVES YOU

abraham linksys
Sep 6, 2010

:darksouls:

bartkusa posted:

Sometimes I see people talk about "routing" with these frameworks, and I'm not sure what that means. Can someone explain it?

http://routing.just/means/urls!

A router is the piece of your application that handles the current URL. In a traditional, server-side model, usually you have some kind of routes.[rb|py|js|php] that determines which controller/view/whatever handles each route.

On the other hand, client-side routing usually is based on one of two things. In both cases, you usually have a single-page app, which doesn't mean that your app is actually a single logical page, but is represented with a single HTML file on the server.
  • Hash routing. So, if you have a file on your server at index.html, because of the way hashes work in URLs, index.html/#/foo will also take you to index.html. A client-side router can then handle the hash bit as if it was a URL, in this case /foo. It's simple to set the current hash in JS, and the browser automatically considers that a new page in your history. Then, your router can listen for the onhashchange event to determine when to update the current "page."
  • PushState routing. This is more advanced, and involves your router pushing new "pages" into the history using the HTML5 history API. This will give you what appear to be the same as a server-side URL, like myapp.com/foo, with no hash. The downside is that, if you've architected a "single-page" app where your application is represented in only a single server-side HTML page, your server's router will need to always send you to the same page, regardless of the URL. So the tradeoff is prettier URLs for a bit more server-side configuration
All three of the major frameworks can be configured to use either of these modes. Hash routing has better browser support, and is usually used as a fallback if you set up PushState routing.

Client-side routing is inherently more difficult than server-side routing because, unlike in server-side routing, your state isn't reset between each page! There's a lot of weird issues that arise because of this. If you've ever been navigating a site, hit back while it was loading, and everything suddenly broke, that's probably because they were using client-side routing (lookin' at you, GitHub).

abraham linksys
Sep 6, 2010

:darksouls:

fidel sarcastro posted:

Is this the same thing people have been doing with mod_rewrite for ages, or am I misunderstanding?

Nah, you nailed it. Of course, for those who eschew writing URL rules at the server level, you can do a simple wildcard route in your back-end of choice.

quote:

What's a typical back-end look like for one of these apps, anyway? Are they pretty minimal, or are you basically just spitting out JSON instead of rendering a view? I'd like to start doing more client-side stuff because I actually like writing JS (weird, I know) but I'm pretty lost with how it all fits together.

You can do pretty much anything you want on the back-end, but the flow is different. It's a bit tricky to explain without pulling out OmniGraffle, but instead of "Server-side route -> get data in a controller -> put that data in a server-side view -> output rendered HTML," your flow becomes "server-side route goes to your single-page app -> client side route figures out what data needs to be retrieved -> ajax call to your server -> return as json -> pull into your models/controller -> render in your client-side template" (with a few other layers mixed in for good measure).

abraham linksys
Sep 6, 2010

:darksouls:

Bognar posted:

What options are there for organizing your templates into different files?

grunt-ember-templates is what you want. If you want to skip actually setting it up, you might want to try Ember App Kit, which includes it as part of its boilerplate. Alternatively, if you're using Rails, the Ember Rails gem will handle templates, too.

abraham linksys
Sep 6, 2010

:darksouls:

fidel sarcastro posted:

Tutsplus posted an entire Ember course for free. No idea what the quality is like, but it might be worth watching:

http://freecourses.tutsplus.com/lets-learn-ember/index.html

I will say that all of the Ember tutorials, screencasts, and books I've seen don't touch on asset compilation/build tools, which are hugely important for Ember. It'd be like trying to teach Rails without using the rails command. If you're interested in Ember, you should look into Ember-Rails, Yeoman's Ember generator, and/or Ember App Kit.

Aniki posted:

I'm not sure what to think about NoSql databases like Mongo DB yet.

FWIW, using a front-end framework (except for something full-stack like Meteor) doesn't require you to go NoSQL! In fact, Ember Data is built specifically to interact with a RESTful API backed by a relational database, and sort of sucks right now with Mongo :v:

abraham linksys
Sep 6, 2010

:darksouls:
For as much fun as we like to make of Jeff Fatwood on these forums, the solution Discourse (Ember.js-based) takes seems to work: it uses duplicated, unstyled markup in a noscript tag. Check out the source here for an example. From what I've heard, it took them like an extra day to implement the server-side templates, though YMMV.

abraham linksys
Sep 6, 2010

:darksouls:

Sorry, should have been more clear - literally right click -> view source on that page and ctrl-f for "noscript" :v:

That's all you need your server to output. In fact, even that has been optimized somewhat to be actually an actual usable page without JS; if all you need is friendly scraping you can get away with less.

abraham linksys
Sep 6, 2010

:darksouls:

xf86enodev posted:

Dude, data comes from the cloud now.

Firebase (a real time key-value store as a service) has an interesting solution for this: security rules that let you limit access to your data. It's very, very simple (and built mainly for keeping a single user's data private to only them), but Firebase is only meant for simple data storage anyways (the real-time aspects are far more interesting than the actual "database").

But just pick something that makes it easy to write a minimal backend or API and you're good to go. We're not quite in a backend-less future, except for very simple use cases (though it is pretty awesome to prototype something w/o a backend).

abraham linksys
Sep 6, 2010

:darksouls:

Top Quark posted:

If you use jshint (perhaps in a grunt task like me) then it will bitch and moan about any strings in double-quotes being wrong. Apparently that thing only likes single quotes for...everything.

"quotmark": false, man http://www.jshint.com/docs/options/#quotmark

abraham linksys
Sep 6, 2010

:darksouls:

Don Mega posted:

We are about to implement a front-end framework at my current small company to replace the jQuery spaghetti mess. We were thinking of using Angular, but with the Angular2 core changing so much it seems like a waste of time. Any thoughts?

I agree with Spraynard Kruger that Angular will continue to be a viable framework, whether or not the very pie-in-the-sky dreams the team has for Angular 2.0 come to fruition or not.

However, I also agree with geetee that React sounds like your best choice. It's a very good library for rescuing jQuery spaghetti without requiring a restructure of how you handle your app's state or routing.

(also lol @ how outdated the OP became in barely over a year. Oh JavaScript :allears:)

abraham linksys
Sep 6, 2010

:darksouls:

Pollyanna posted:

One problem that Flux has is that it exposes too much of the internal wiring, it feels like. Being expected to build an EventEmitter for every Store I make feels like busy work and like something that could be automagically abstracted away for me. I've got a reading list of React stuff to go through, so I'll try and see if there's a better explanation of it somewhere.

You can use one of the other Flux implementations around that hide some of the boilerplate; I've been using Fluxxor and it works well enough.

It makes it a little easier to reason about getting data from Flux - it has a FluxMixin that lets any component get any store, as long as either (a) it gets passed a Flux instance as a property or (b) it has a parent with FluxMixin that was passed the Flux instance. This means you can have a complex tree of components, all mixing in FluxMixin, and as long as the top-level component was passed Flux, all of the children can access it. That way, instead of managing a wildly complex props tree, you can do something like:

code:
render: function() {
  var currentContact = this.getFlux().getStore('ContractStore').currentContact;
  return <span>{currentContact.name}</span>
}
It also has a mixin that handles binding to changes in your store, which takes away a boilerplate. Plus, since Fluxxor still just uses an EventEmitter for its stores, you can add custom events when simply emitting that state changed isn't enough (which, in my experience, is a pretty serious issue with Flux).

abraham linksys
Sep 6, 2010

:darksouls:

PlaneGuy posted:

this scoping is one of the most confusing things for me learning JS (protip: it gets worse in ES6)

Eh, learning that this is auto-bound in arrow functions isn't as bad as what I learned when porting some code over to Babel, which is that arguments in an arrow function is actually the same as the parent function's: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions-runtime-semantics-evaluation

I don't understand why this decision was made, other than to actively gently caress with new coders :v:

Thankfully, arguments can be considered deprecated in ES6 anyways, and replaced with spread operator (e.g. (...args) => {...})

abraham linksys fucked around with this message at 01:48 on Apr 2, 2015

abraham linksys
Sep 6, 2010

:darksouls:

piratepilates posted:

Taking a trip down the node_modules rabbit hole for one of your projects is fun. Half of webpack's size is due to a dependency called 'source-map', which is maybe 100kb or so but contains a benchmark suite that has a 16mb file that just appears to be a Scala.js runtime.

looks like there's a newly-added npmignore for the project that should help, at least: https://github.com/mozilla/source-map/blob/master/.npmignore (see https://github.com/mozilla/source-map/pull/169)

abraham linksys
Sep 6, 2010

:darksouls:

EkardNT posted:

How would you handle purely widget-related/UI state in a redux application? I'm talking about stuff like dropdown open/closed, selected tab, etc. It gets very cumbersome very fast to make a reducer for every single instance of a widget in your application...

If the state is purely encapsulated to the state of the component, you can just put it in component state.

If the state has an impact on the other state stored in Redux, then you probably want to have it in Redux. You can still keep your components somewhat isolated if you use event handlers & props to pass state up and down the tree to/from your Redux-wrapped components, or you can just tie your components into Redux, whichever makes sense (see how this example is structured: http://rackt.org/redux/docs/basics/UsageWithReact.html)

abraham linksys
Sep 6, 2010

:darksouls:
tangential to the current discussion: having done React TDD at my last gig, and now working on a codebase where I haven't written any tests for components (just Flux stores)...

React testing frustrates me because the declarative nature of React makes certain guarantees on your code. I wouldn't, for example, write a test like "renders elements passed in," or "has a click handler," for the same reason I wouldn't write tests making sure my CSS rules made an element red - there's no logic to test there. The tests that I wrote at my last gig were pre-Flux, so they were testing things like complex action/state code inside components, and obviously if you have that you want to test your components. But when they're basically blobs of JSX that render props and maybe have an event handler that calls a Flux action... I dunno, it just seems like pointless boilerplate.

Y'all who do write tests for components, how do you scope it?

abraham linksys
Sep 6, 2010

:darksouls:
I've stripped jQuery out of my React apps (I think, should probably inspect my webpack bundle to make sure some dep didn't sneak it back in there)

$.ajax was the big remaining holdout, and window.fetch is still a garbage-tier API (hope you bring your own query-string library for GET requests!! :downs:) but is at least better than XMLHTTPRequest unless you need to abort requests (which I don't think $.ajax let you do anyways?)

abraham linksys
Sep 6, 2010

:darksouls:
my main problem with Redux is that it requires higher-level abstractions and no one has agreed upon a set of sane defaults. you end up with (as this excellent article mentions) a combination of a bunch of middlewares and home-rolled abstractions for things like reducer boilerplate or async action state that should really be solved by now

I like it a lot and I think we'll get there, it's just frustrating at the moment

abraham linksys
Sep 6, 2010

:darksouls:
I should probably sit down and figure out redux-saga but every time I try to read an explanation like this my eyes glaze over and I retreat back to redux-thunk which is more than enough for my basic HTTP request needs.

That seems like a solid enough stack for what you're trying to do. PostCSS/Rucksack is pretty immature and I'd probably recommend SASS instead, but it's probably not something that's going to be annoying if you change your mind later.

abraham linksys
Sep 6, 2010

:darksouls:
fwiw you can get away with using old versions of React/libs if you want, my main project is still on react-router 0.13.x and some old Flux implementation because it works fine

React itself has had little enough churn that it's not hard to use old libs with new versions for now, haven't had any major compatibility issues

abraham linksys
Sep 6, 2010

:darksouls:
npm install --verbose might give you enough output to help you debug this. also worth trying an `npm cache clean && rm -rf node_modules/`, sometimes you can end up with weird cached or local dependencies that are no longer actually used

abraham linksys
Sep 6, 2010

:darksouls:

Plavski posted:

But anyway, ya'll shouldn't be using Angular 2 cos it's non-standard garbage :)

http://aurelia.io/

Aurelia - it's like Angular 2 but standards compliant, smaller and faster. It's much nicer to code and has proper separation of church-and-state so your HTML and JS don't need to mix and get confusing as gently caress. We've adopted it for our next enterprise product and it's amazeballs. You don't have to teach anyone "aurelia" cos everything is pure standards-compliant HTML and JavaScript with only the barest of conventions. It's really, really nice and has skeletons in ES6 and TypeScript.

explain to me how Aurelia is "more standards complaint" than Angular 2. Last I checked, Angular 2 doesn't require a bunch of non-standard APIs to be implemented in the browser running it or something. just because something has a build step doesn't make it "less standards compliant"

abraham linksys
Sep 6, 2010

:darksouls:
React does need control over the tree its mounted on, though. Like, you can mount a React application over an existing rendered tree, but you need to be able to render the same content through React, which is non-trivial in a lot of cases. If Angular having "total control of templates" was a dealbreaker this may be an issue for you.

abraham linksys
Sep 6, 2010

:darksouls:
ember doesn't have any one big company behind it but still has plenty of small shops and mid-sized mature companies using it, idk (twitch, digitalocean just moved back to ember after trying react for a while, etc)

abraham linksys
Sep 6, 2010

:darksouls:

Suspicious Dish posted:

i can't find anything about twitch trying react at all. in fact, the only mention of react is a job posting suggesting they do use react:

https://jobs.lever.co/twitch/888a6a8b-3cff-4c90-b490-33852910713e

twitch uses ember. digitialocean used ember, moved to react, and are moving back to ember

the closest thing ember has ever had to a big company backing it is yahoo, and there's no one in 2016 going hell yeah, yahoo trusts it!! but ember still manages to do very well without big co support

abraham linksys
Sep 6, 2010

:darksouls:

Noam Chomsky posted:

Nah, man, you should only use things used to build the most popular apps that have ever existed, otherwise you're a scrub, also when they switch stacks, you should definitely switch stacks, or you're a scrub. Context doesn't matter; only hype.

my favorite part of the people who adopt this awful strategy is when they don't even stop to consider that massive enterprises have different engineering needs than new startups or small client projects. For example, Relay/GraphQL is something that made sense for Facebook because they had the resources to write their own backend to implement their own query language. It will not make sense for your tiny three-man engineering team. Heck, even Flux is boilerplate-heavy in nature because the teams at Facebook who make apps with Flux can afford to trade coding speed for the explicit nature of Flux makes.

abraham linksys
Sep 6, 2010

:darksouls:
I wrote a lil thing on Webpack a few weeks ago that may help if you're specifically wondering how it differs from, say, a Gulp/Browserify setup http://devlog.disco.zone/2016/06/01/webpack/

But yea Thermopyle covers it. The full ES6 module support coming in Webpack 2.0 should be very cool (and I'm excited that it apparently doesn't break the API very much!), bringing Webpack up to parity with Rollup.

abraham linksys
Sep 6, 2010

:darksouls:
fwiw there was an earlier version of the patent grant with way less clear language, this version apparently had sign-offs from a couple concerned larger companies (including Google)

abraham linksys
Sep 6, 2010

:darksouls:
shot in the dark, but it's not fixed if you add "allowSyntheticDefaultImports": true to your compilerOptions, is it? there's some weird quirk about TypeScript doing ES6 imports of CommonJS JS modules

abraham linksys
Sep 6, 2010

:darksouls:

Suspicious Dish posted:

OK. I have a problem.

I write a bunch of cool web toys. I want to try out using TypeScript on one of them, because I keep making dumb type errors. My preferred workflow: in Visual Studio Code or Atom, have TypeScript. If I press F5 on the right in my browser, I should get JavaScript that is up to date.

I do not care if I use Gulp, Grunt, Broccoli, or Webpack. You pick the tech stack and tell me how to set it up. I just want TypeScript automatically compiled when I change something. Maybe some nice debug integration.

Go.

for applications, webpack's relatively easy! I use it (via ts-loader) for Manygolf and a couple other TypeScript apps. for libraries the question gets trickier, because you don't really want to output a bundle, you want to output a bunch of commonjs files something else can bundle, and webpack isn't built for that. i've recently used gulp for that task, but i don't love it, and have considered a broccoli-based build (though gulp is far easier to work with, so if you just want to get up and running ASAP, it's the way to go)

on the editor front, i'd recommend using vs code purely because atom-typescript, last i checked, was buggy and its lead maintainer had lost interest in the project

Skandranon posted:

I prefer Gulp, it can be as simple or complex as you want it, and flows nicely from a JavaScript point of view.

yeah, gulp would be pretty good for that use case. you could use gulp as a wrapper around webpack for one or more of those tasks (especially the Angular 2.0 application and probably the Knockout application?).

webpack's really good if you have "an application" you want to build, as i mentioned above. so, like, you'd have a webpack config that builds your angular app, and one that builds your knockout app, and you could have those as npm scripts or gulp tasks.

you could also use it to build that common bundle included on a lot of pages, plus smaller split bundles for your other pages - that's not hard at all to do with webpack (assuming you're using a module system!); you're just defining multiple entry points :)

for your scss -> app.css, webpack could handle that, but it would make the most sense in the context of a single app. if those 4 different apps you have are all using the same CSS, and you only want to build it a single time, i'd recommend that be a separate gulp task

abraham linksys fucked around with this message at 05:39 on Oct 26, 2016

abraham linksys
Sep 6, 2010

:darksouls:
I spent 2014-2016 mostly working on a financial product with a tiny user base (that, uh, never launched, at least not yet). Then I started a new job late last year, and now I'm shipping product to tens of thousands of users again, which has been an interesting adjustment. Definitely a lot of "hurray we shipped and people like it!," but also a lot of "oh god it's broken oh no."

Doing a lotta things to improve confidence shipping lately. Set up Bugsnag (though we get a ton of noise from lovely third-party scripts our marketing team injects that just break all the drat time), now giving Percy a shot for regression testing. I've wanted to use Percy for a while, but this is the first time I've worked at a company that actually had the budget and the right stack for it (it just goes right into our Capybara feature tests).

Really recommend setting up something like Bugsnag (or my personal favorite error reporter, Sentry) for any new app, even if it's small. It's nice knowing that when a user says "hey, your thing broke," it's probably possible to go and find exactly the exception that got thrown.

We've also got feature flagging set up, and I'm basically putting literally every new product release under one, so that if it breaks we can shut stuff off. We have a great customer service team that's really good about reporting real problems upstream, so whenever we've had a major bug we've heard about it quickly and been able to disable the feature, which lets us take our time instead of trying a panicked hotfix.

Working on a live product is fun, though! I realized I kinda missed it. It's nice to go off and architecture astronaut your way to the Perfect First Release, but there's a neat set of challenges in updating live software too.

abraham linksys
Sep 6, 2010

:darksouls:
very open-ended question here: anyone using Vue + TypeScript? loving around with a personal project rewrite in Vue (really interested in the SSR stuff), but it seems like Vue+TS is spotty enough I'd maybe benefit by just dropping TypeScript. specifically, stuff like "can't type-check this.$store inside a component definition" seems like a no-go. if it were just a lot of any types I'd keep using TS just so I don't have to, like, set up a babel config and at least have type checking on a few things, but I'm getting straight-up errors when trying to write some of the code like in the SSR guide because the type defs don't take into account adding injecting and adding things to components (like the asyncData method)

setting up Vue+SSR has been pretty okay other than that. the worst part was that the SSR guide is awesome and detailed on setting up Webpack, how to architect your code, etc., but then doesn't tell you how to set up your dev server at all - I had to copy-paste a lot of stuff from the official example repo to create a dev server that watches and builds the multiple Webpack bundles you need.

also, I kinda just shoved the SSR server into my existing Node API server, which sorta works, but has a funny problem in dev: when I change API code on my server, it has to restart whole server to go into effect, and this requires the server to rebuild all the Webpack bundles in dev (since it's not cached between runs). this isn't a problem with the actual Vue codebase, which just triggers a Webpack rebuild and not a server restart, but means that I probably need to split my API and SSR servers. that actually might make it easier to treat the SSR server as a "client" to the API server, I guess?

in general I'm kinda worried about building out the API-client bit of this app and making sure it works on the client and server, but it looks like the trick is relatively simple:

- use a universal JS lib for making requests (axios seems like the most common choice)
- for authentication, use cookies to store an authentication token, so your SSR server has access to a client's token on request (as opposed to localStorage, which would only be visible from the browser)
- pass the authentication token from cookies into your app's store on both the server and client
- attach the token from the store to all API requests

honestly not that bad. the other thing I'm kind of bothered by is that I'm going to end up doing multiple HTTP requests for authenticated users - one to get the current user, one+ to get the rest of the data required by the page - and I feel like that's got some of the same overhead problems as doing multiple HTTP requests from the browser? maybe this is over-optimizing, though (as if SSR for a toy app isn't over-optimizing by its nature, though hey, at least now I'll have better <meta> tags for rendering Twitter cards or whatever)

abraham linksys fucked around with this message at 19:07 on Mar 14, 2018

abraham linksys
Sep 6, 2010

:darksouls:

Nolgthorn posted:

There are no assertions in this example because when I remove the assertions the thing still hangs. All of the tests complete which means my async functions are finishing and the assertions all pass. Then it hangs saying "1 passing (266ms)" and sits there.

could be some kind of long-lived connection/event listener preventing node from stopping? i don't think your database connection would be an issue, but something in that regard?

potentially useful is one of my favorite-named npm packages ever https://github.com/myndzi/wtfnode

abraham linksys
Sep 6, 2010

:darksouls:

Nolgthorn posted:

It seems like, using this tool, and I could be wrong... is it possible, that a library as large and as popular as knexjs is the culprit? I would love to say no but when I inspect this it seems like knexjs leaves an open socket and one of its dependencies leaves a running interval.

What the heck??

God I feel like I hate this industry sometimes.

Interesting! I use knex and I don't think I've had this problem, but I also use this trick to ensure all db interactions are captured in a rolled back transaction, which might help?

https://github.com/thomasboyt/jam-buds/blob/master/api/src/__tests__/index.spec.ts
https://github.com/thomasboyt/jam-buds/blob/master/api/src/db.ts

abraham linksys
Sep 6, 2010

:darksouls:
lotta places I've seen limit it so that feature tests only run on PRs into master. you gotta be careful with that stuff and make a coherent process, though.

once worked at a company where feature tests took ~40 minutes and were supposed to be manually run before you merged, and engineers were really bad about just... not... running them, or running them early while working on a feature but not running them on the finalized commit set. we did have it set up so that they ran automatically before deploy to staging on master, as part of our larger daily deploy process, but it loving suuuuuuuuuucked when that failed and the deploying engineer had to ping every engineer who had merged in new commits to figure out who broke it

abraham linksys
Sep 6, 2010

:darksouls:
what's your build pipeline like? if you're importing these SVGs through like Webpack, it should be relatively easy to split them out to a chunk that gets lazy-loaded. I haven't used that stuff much but I think you could do something like import() to basically grab every file matching a given regex, so you can e.g. load all the SVGs in a specific folder

alternatively, if they're already reasonably optimized, just leaving them as static files that don't go through your build pipeline and referencing the urls directly seems fine?

abraham linksys
Sep 6, 2010

:darksouls:

IAmKale posted:

...Can't you use a regular <img> tag and manipulate its height/width/colors/etc... like usual? The SVG should adapt as expected and the otherwise static assets can be served from a web server without bundling them into the app itself :confused:

fwiw if https://svgontheweb.com/ is to be believed, you actually can't (which i knew for background-image but not for an actual <img>). you sorta can for <object> but it requires injecting a stylesheet into the content I guess?

for inline, if you're using webpack, you can still lazy-load individual chunks for svgs with either svg-sprite-loader (which does fancy deduplication stuff) or just raw-loader (which doesn't). i thought you could use import() for this, but that doesn't actually support the use case of "iterate over all files in a directory" (though it would work if you had an explicit list of icon names). you can instead use the older, but afaik not deprecated, require.context() API

I was bored so I put together a demo showing this here https://glitch.com/edit/#!/webpack-folder-load. it uses webpack's raw-loader, so each raw svg gets turned into a lil JS chunk that just wraps the SVG content. you can iterate over the list of items in the folder with the requireContext.keys() API, which is what's used to show the buttons, but each chunk isn't loaded until the button is clicked and `await requireContext(key)` is called.

abraham linksys
Sep 6, 2010

:darksouls:

Dominoes posted:

What do y'all use for testing? I'm giving Jest a shot, but the official tutorial doesn't work with es6 imports, (or perhaps webpack/TS? ie note at the bottom of the page and other cues imply Jest is only straightforward to use if using Babel) and it appears the solutions involve messy config changes.

Leaning towards moving the calcs to a Rust/WASM module and using Rust tests.

i am... fascinated by the idea of a world in which someone could have so much trouble with the idea of throwing a two line babel whitelist into their jest config file that they switch entirely over to rust+wasm

godspeed i guess

abraham linksys
Sep 6, 2010

:darksouls:
before i went all-in on typescript, i used to use create-react-app to spin up any lil demo thing i had. it's pretty nice, though i think tooling usage has simplified pretty drastically over the past couple years, even as tooling usage increases

i think the trickiest part of tooling is still weird environment mismatches, which is exactly the jest problem. like, the whole issue there is:

- since webpack 2.x, it is no longer considered best practice to precompile es modules to commonjs. instead, webpack now has full es modules support, and can easily transform es modules to its own internal module format for packaging. so your babel or typescript compiler should be configured to output es modules for webpack to consume
- on the other hand, jest does not have any kind of special es modules support, and runs your code in a standard node runtime, so you need to compile source and tests to commonjs for imports to work
- now, jest does have built in babel support, so for this compilation, you "simply" need to add environment-specific config for babel. i say "simply" because you have to identify the problem and know to dig into the docs to this point to figure out how to fix it, which isn't intuitive
- however, that's actually different if you want to use jest with typescript, since that's not using babel at all. you can instead add the ts-jest package and use it instead of babel. there's some configuration there, but, hey, fun fact, it actually automatically configures typescript to output commonjs when running tests, so that's nice

so when we talk about these opinionated tools like create-react-app and vue-cli and whatever, these sorts of problems tend to end up being really hard to handle without being entirely opinionated in terms of every level of your stack ("okay, this tool will wrap typescript + react + jest + these other dependencies...") or ending up just being boilerplate that you still have to manually adjust yourself (the create-react-app eject problem)

all of this to say, i use these sorts of issues as justification for continuing to cart around my bespoke handcrafted artisinal webpack config from project to project, and try to learn and stick with a specific stack so i know how to solve problems within it. especially given, as i mentioned at the start of this, i use typescript for almost everything (except vue, but i'm hoping that'll change), and all of these zero-config tools generally require a heck of a lot of config once you bring that in.

at least you can now transform typescript via babel, so tooling might get simpler there, though i'm a bit wary of losing build-time type checking, since vscode doesn't have any good way to do constant project-wide checking, afaik (only open tabs)

abraham linksys fucked around with this message at 23:10 on Aug 27, 2018

abraham linksys
Sep 6, 2010

:darksouls:

spacebard posted:

The most frustrating part of my day is trying to work with the combination of angular's unit testing modules or protractor. It feels so obtuse and clunky. It's also half typescript where everyone is all like "whee, privates and readonly this is just like the back end, right!" and go hog wild making things as untestable as possible. :bang:

i've been really digging into writing tests with mocks for a typescript app for the first time and found this to be a pretty large problem, yeah. at the end of the day i just sorta... gave up and started mocking and using private methods, which you can do very easily in typescript (literally just used indexed access, e.g. myObject['myPrivateMethod'] = mockedMethod). i try to use it sparingly when it helps me avoid setting up complex dependencies for an object, so that instead of e.g. setting up a mock websocket to fire an event so that a class's private onMessage() listener gets called, to just... directly call onMessage(). bonus points if this test logic is extracted to a helper function (like "handleTestMessage(object, msg)"), so that logic depending on private properties only exists in one place that will be easy to change.

i will say that jest + typescript is pretty fun, because you can do things like ensure you fully implement a mock class. so if you did want to implement a mock class, like a websocket wrapper:

code:
// in src/__mocks__/Socket.ts
import Socket from '../Socket';

// simple mapped type that only extracts the *public* part of an  interface
type PublicPart<T> = { [K in keyof T]: T[K] };

export default class MockSocket implements PublicPart<Socket> {
  // this class only type-checks if all of Socket's public interface is reimplemented,
  // but you can just use jest.fn() for the actual "implementation"
  send: (msg: string) => void = jest.fn();

  // or a custom implementation so you can e.g. fire events as would actually happen
  // in your real class:
  connect(): void {
    this.emit('connect');  // or whatever
  }
}

Adbot
ADBOT LOVES YOU

abraham linksys
Sep 6, 2010

:darksouls:

prom candy posted:

If you're using Rails you can use the react-rails gem, which lets you write template code like:
code:
<%= react_component("Comments.NewForm", {post_id: @post.id}) %>
This sucks a lot compared to properly separating your front-end and your back-end but if you just need to add a bit of interactivity to server-rendered templates it works fine.

jeez, I've been building React apps on Rails at my last couple gigs but hadn't actually seen this before. I knew there was a react-rails gem, but I always thought it was just JSX compilation inside the asset pipeline or something. This looks pretty nice.

Currently I've just been doing something like this in each of my templates rendering React apps (butchering the syntax here a bit):

code:
<div id="app-root"></div>

MAGICAL_GLOBAL_NAMESPACE.pageData = {
  dataAppNeeds: <%= raw @data_app_needs.to_json %>
};

<%= javascript_pack_tag "react_app_a" %>
<%= stylesheet_pack_tag "react_app_a" %>
And then have the root component include the page data as props:

code:
const {pageData} = MAGICAL_GLOBAL_NAMESPACE;
render(<ReactAppA {...pageData} />, document.getElementById('app-root'))
That said it looks like that helper tag basically handles that hand-off for me which seems real slick. Have you seen any tradeoffs with that Gem? I assume the integration with Webpacker pretty much works as you'd expect?

FWIW this is more or less a stopgap until we merge our user-facing app into a single SPA, which we're going to do simultaneously with building out some native apps, meaning we'll actually have GraphQL or RESTful GET resources for things that are currently just being loaded in the page template. Still, there's nothing really wrong with it other than the boilerplate, and I think for now it's easier than if we tried to build GET/GraphQL endpoints and add loading states for each of our React apps. Webpacker makes it easy to build a common shared vendor bundle between them, too, so you're not pulling in a bunch of redundant JS when transitioning between apps. It... kinda gives you some of the benefits of code-split/lazy-loaded SPAs by default, lol.

abraham linksys fucked around with this message at 00:42 on Nov 24, 2018

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply