Talks

How Sprockets Works

EuRuKo 2016

00:00:04.520 and our next speaker is Rafael franka he comes from Brazil and he's one of the
00:00:10.040 most vibrant rails contributors the most frequent rails release manager and also
00:00:16.920 known as the rails patch monster so he works at Shopify and he'll tell you
00:00:22.760 about
00:00:28.519 sprockets hello every everyone I'm here to talk to you about how Pro works but
00:00:35.040 first I want to know how many of you knows how this SP really works so please
00:00:41.280 raise your hand if you know how that works oh we have two three I think three
00:00:47.120 people knows how that works that does not include me because I don't know anything about it
00:00:53.840 so yeah that's not true uh but I not the original maintainer of the project
00:01:00.559 so this pro project was created by Josh P in St Stenson from base camp
00:01:07.640 originally and since the last year Josh left the project and no one in the r
00:01:15.000 called knew how his Pro works so this talk is exactly my try to understand how
00:01:22.840 his Pro works and to show you in the community how it works originally so
00:01:29.680 like like it was said I'm Rafael fra is hard to say my last name
00:01:37.840 so you can find me in GitHub as Rafael franka and Rafael franka also in Twitter
00:01:45.200 I'm member of the Ros Scot team and I work at shop so one thing that I really like
00:01:52.840 about the Ros Scot team is that we are allowed to work you anything that we
00:02:00.479 want to work so some people like to do interesting and exciting things like
00:02:08.360 implementing new Fe features and also make performance improvements but to people be able to do
00:02:17.200 that someone had to do the hard Bing Shob so I the person that do that Bing
00:02:24.080 job so I can say that I'm the ra Mainer like it was said I
00:02:30.400 was the relas manager of the last three years and I'm always dealing with issue
00:02:37.959 trackers and Reporting and review Pro requests and not just in the Ros story
00:02:45.440 itself but the r project has a lot of different components that you can most
00:02:52.879 of you already are familiar with then like action view action controller activ
00:02:58.120 records but we also have things R is present in all the
00:03:04.000 layers of your web development framework like you
00:03:09.440 have things at the process level like spring we you have the MVC stack
00:03:15.480 framework you have things running the browser that are part of the Rails
00:03:20.640 project like JJs in links and you have the asset pipeline that is what I'm
00:03:27.239 going to talk to you today so this is is the agenda of this talk
00:03:34.040 first I need to to tell you why do we need a asset Piper line and what that
00:03:41.760 means what are the J responsible for the asset Piper line inside the rails how it
00:03:47.480 works in a ra application and how to extend it so first why do we need asset
00:03:55.519 pipeline before the ra 3.1 we raos had no conventions how to organize
00:04:04.360 your assets apart to that you knew how to organize a real application you have
00:04:10.400 folds like app models app controllers but all the Assets in that time were put
00:04:16.880 in the public folder so there were were no convention in that
00:04:22.720 time how to organize assets and usually you end up with a lot of files that you
00:04:28.800 don't know even if they were be used or not in your
00:04:33.840 application and also in that time you had to do some tradeoffs between code
00:04:38.919 organization performance like should I use small s
00:04:44.160 contained files that's better for modularity and maintenance of the code
00:04:51.360 but it's also create more request to the from the browser to the web server so
00:04:58.520 that could C better wor performance in your client side so should I take this way or should
00:05:07.639 I make few asset requests like maintaining one huse file that is hard
00:05:14.960 to maintain and also do he use components all the three off that where
00:05:21.600 common that is was should I write legible code with dtive name and code
00:05:28.479 documentation or should I send a few bytes to the users so the connection
00:05:35.280 very faster in you can get your page faster and also in that time we have you
00:05:43.440 had new technologies being used like CP SAS and recently
00:05:50.360 es6 so to solve all those problems we introduces the rail assess
00:05:57.840 Pipeline and how it's working right now in raos so
00:06:04.039 now we have conventions for the assets all the assets live in the app assets folder so you have folders for St shets
00:06:10.960 you have folders for JavaScript you have folders also for images so is easier to
00:06:16.039 know where each component of your client side is present and you can also have
00:06:24.360 assets inside the Le in Vendor and the assets are compiled on
00:06:30.160 the fly in development and need to be pre compiled in production apart from that is pro also
00:06:37.720 set good standards like you are able to cash out your
00:06:43.840 assets in the client sign for forever and his pockets will be able to do cash
00:06:52.160 busting setting uh digest in the name of the assets
00:06:58.400 itself now that you already know how the assas pipeline Works in rails I going to
00:07:05.360 talk about the Gen that are responsible for this Behavior so we have several chains that make this
00:07:12.160 possible sprockets sprockets rails size rails isgs in C
00:07:18.120 rails the spr Gen is the principal gen of the setup what it does is compile and
00:07:25.639 service assets and it's as it is a simple process pipeline like
00:07:34.080 you have a pipeline made of different processors these Pro key components are
00:07:41.759 processors to S components directives environment manifest and pipelines are
00:07:47.840 going to talk about one of each of those so the processor is the most
00:07:55.680 important component of sprockets it is any cable object that
00:08:01.840 accepts input and returns a hash of metadata so this is one of one simple
00:08:09.840 example of what is a processor inside sprockets is just a Lambda that receives
00:08:17.080 input is a hash and ret return another hash with the data and some
00:08:24.159 metadata so what this processor is doing is removing all the sem colons in the
00:08:30.319 end of your JavaScript files because you don't need semicolons in
00:08:36.080 JavaScript so the input hash is consisted of those
00:08:43.640 information like you have the data of the assets itself you have the environment that is a instance of this
00:08:50.720 proess environment you have the cache thei The Source path load path name
00:08:57.000 content type and metadata and you have to return another hash that
00:09:03.959 is simpler than this one the only required information the data itself so
00:09:10.079 you have to return the data that is going to be used by the next processor
00:09:15.600 in the Shain and you can also provide some metadata like all the required
00:09:21.200 assets that you need to build that asset links that you have to external assets
00:09:27.640 other dependence the Source maps of the assets and also the M type this Pro come with some bu
00:09:37.519 processors like the most common are the S processor and the C processor and the
00:09:45.040 verion four of sprockets also have a bable processor to compile AC script six
00:09:51.560 files to JavaScript one special kind of processor
00:09:56.680 is called bundle processor it is a processor that runs concatenated files R
00:10:05.000 the individual files this is how you
00:10:10.320 register a processor in sprockets so I'm saying that to bundle all the assets
00:10:16.720 together I'm going to use the processor called bundle the same thing for
00:10:23.200 CSS what the Bund bundle process does is to take a single file of assets it
00:10:29.839 prends all the URL that's uh to the contents of these
00:10:36.160 assets I'm going to explain that later another kind of processor that you
00:10:41.720 have are the Transformers they are simpler than the general processors
00:10:46.839 because they know how to convert one file from one format to another format
00:10:53.639 like we have the CPT processor that only transform cof scrip in Javas
00:11:00.480 and the implementation of any processor is the same is any colable object so the implementation of the C processor is
00:11:07.680 something like this you have a call method that receive a input and also
00:11:13.839 return another hash and what is important in this implementation is that
00:11:19.399 what this processor does is actually compiling the data that was read from
00:11:26.240 the file system to JavaScript and returning that data later to the next
00:11:31.519 processor in the Shain we have also have the compressors
00:11:36.680 and the compressors are a special type of bundle processor the difference
00:11:42.800 between compressors in any kind of processor is that it has a special way to to declare
00:11:52.600 them and also to use like this is thei compressor that take inal code and
00:11:59.560 compress in minif Fes to create few bytes when you are saving and to use uh
00:12:07.399 compressor you have a special API that you need to specify for each type of you we only
00:12:15.360 have two compressors the GS compressor and CSS compressors so you have to
00:12:20.480 specify which compressor you want to use when you are trying to compress
00:12:25.880 JavaScript for example also has
00:12:31.000 directives those are the most common things that you see in ra application
00:12:37.440 like directives are the those special commands that decare the Bund in
00:12:43.839 theis this is the example of the directive is being used I have a application GS file
00:12:52.600 that depends on you carry you carry Y and also in the user files and also ire
00:12:59.480 all the files in the same tree so this is the definition of my bundle my application yes
00:13:07.000 bundle and to use that in the application you have to register this
00:13:12.519 bundler in the pre compile configuration this is the content of
00:13:19.240 your config envirment asset file and this is
00:13:25.760 saying that to generate my application I have those two bundles the application
00:13:31.399 GS the application SS you usually don't need to do that because this is the defa
00:13:37.240 of any Ros application so by the raos Define three two thingss on the pr
00:13:44.600 compile list that is this strange Lambda
00:13:50.160 that is saying that any file that's not CSS or GS is going to be back compiled
00:13:56.000 like image and mp2 and videos that you have in your asset
00:14:02.959 folder and also in file that's name application is going to be precompiled
00:14:09.639 there is a problem with this approach because it's not easy to understand what's going to PR compile Don not and a
00:14:16.759 lot of people had problem with this setup so in spet 3 we introduced a new
00:14:24.079 kind of bundler that is called manif file that is coming by the in any r five
00:14:33.040 application so this file is a simplification of that PR compile Lambda
00:14:39.440 and configuration that is basically saying in a more declarative way which
00:14:45.800 assets are going to be PR compiled so I'm saying that I need all the images
00:14:52.279 inside the image fold that I need all the GS file inside JavaScript all the
00:14:57.360 CSS file inside sty sheets and I also can say that I want all the assets that
00:15:03.839 are inside my machine there are several directives by
00:15:09.839 theowing in sprockets the most common one is the required D directive but you
00:15:16.240 can also use require self link depend on and depend on
00:15:24.160 asset another object that is important in spets is the environment and the
00:15:30.440 environment is the main object inside this spets because it is exactly what has methods
00:15:39.040 to reive in s assets to manipulate the load path into registering
00:15:47.199 processors so this is how we usually use our environment I'm telling this code
00:15:54.399 that I need to compile the application GS file the this is how the javascrip
00:16:02.319 Tex works and I can also specify new Transformers like I want to transform my
00:16:09.079 SVG file to P using that Transformer so the environment always
00:16:15.600 compiles the assets when you ask to so every single asset that you ask to the
00:16:21.399 environment is going to be pre compil the fly that's a problem with production because you don't need to always
00:16:27.639 precompile the same file so to fix that we introduced another object that's
00:16:34.160 called manifest is the same name of the configuration but different thing and
00:16:41.399 the Manifest is a object that logs all the contents of the assets that are
00:16:47.560 precompiled inside the directory and also have a caching so you
00:16:53.279 don't need to promile every single time you access asset
00:16:59.000 it's a really simple file that points aspf to finger pint versions like when
00:17:05.160 you do this in your views you are calling JavaScript include tag with
00:17:10.319 application the Manifest is responsible to get that name of the file that is
00:17:19.679 used as the source of the script so that file is basically a j file that points
00:17:27.400 the the path of the asset to the fringed
00:17:33.200 version of that asset and there is also the another way that from the finger pit
00:17:39.840 version you know what is The Logical path the a type and Das of that
00:17:45.880 file this is us it to to cash inv validation so every single time that you
00:17:51.600 change asset PR again SP already know how to do that so you don't need to
00:17:57.799 delete the cash at all there are more components inside the
00:18:03.159 spets that I'm not going to talk about because they are also simple or not
00:18:08.559 relevant to this stock like M types dependenc resolvers the S suffix bundle
00:18:14.799 metadata huers they are mostly used by extensions of sprockets that you can
00:18:21.600 make in like gen and another gen that I going to talk
00:18:29.400 about this Pro ra gen like the name can point to you it's a way to integrate
00:18:36.559 sprockets to raos application because sprockets are part of being used in raos can be used in any kind of application
00:18:44.480 even if you just agree in Elixir
00:18:49.640 application and what this SPX R does is Define helpers in your rubby models like
00:18:56.880 those two helpers are def fin by spus raos and it also configures the spus
00:19:03.880 environment using the raos configurations another thing that SP
00:19:08.919 raos now does is check the pre compile list because before we had the check it
00:19:15.559 was really hard to understand when your application have problems with your
00:19:20.840 assets so if you were pointed to wrong asset like you have a typo in the name
00:19:27.480 of the asset you would only see this problem in production when I asset was not going to
00:19:35.080 be served because the name is wrong but now you can see this beautiful EO page
00:19:41.360 that say you're trying to serve asset that's not in the pre compile list
00:19:48.039 please fix that by adding this file to the pre compile list or actually fix
00:19:53.799 your typo the another change that you have in this Pro setup is the size rails and it
00:20:01.600 does the same things that this Pro ra does that integrating the size processors with the raos
00:20:08.400 application it generates it defines the generators like when you generate discal
00:20:14.720 fold the application css. SSS file is going to be generated by
00:20:21.400 D it's also create import that knows how to handle Globs and erbs because the
00:20:28.640 size processor by Thea doesn't know anything about Erb or even glob path so
00:20:36.360 this is only possible if you are using the size R because the first line in the
00:20:43.480 glob the globe imported is is not building the size itself and the second
00:20:50.200 one the IB processor needs to be also declared in the Gen and it l it's
00:20:58.080 configur this processor the exgs Gen is a gen that was made to allow
00:21:06.880 you to run jav code inside your Ruby process you may be asking why should I
00:21:14.320 want to do that yeah but one of the things that
00:21:19.360 this is useful is that it's uses the JavaScript environment that is available in your
00:21:26.000 machine so if you have uh Windows machine is going to use the
00:21:31.559 Microsoft Windows script host if you have no GS in
00:21:37.080 your machine is going to use the no GS and there are a lot several options of
00:21:43.640 environments for japt and we need that because for instance we want this spets
00:21:51.559 that is a h programing to compile C script we could write our own C
00:21:59.000 compiling Ruby but that would be at least inefficient because you would be
00:22:05.840 duplicate work so we actually use the same compiler that in JavaScript library
00:22:12.000 use that is the C compile and this gen is what make
00:22:17.679 possible to us to run the same C compile inside the rubby
00:22:24.000 process so the is used by the CP to comp C script and many others use that we
00:22:31.400 have and speaking C script we have also the cscript ray chain that only configur
00:22:37.720 the generators so if you don't need generators you don't need the gener
00:22:43.039 all it's also defines a template Handler so you can serve C script files inside
00:22:52.000 your controller and so how the assets are generated in
00:22:59.960 development like I explained all the ches but how they work together in my R
00:23:06.720 application so say that you have a JavaScript include tag in your yourb
00:23:12.080 file your view and like I showed before what this is going to do in development
00:23:19.279 and production is generate a script tag with a source that points to uh where we
00:23:27.679 that is inside his proct itself so your Brer is going to do a get request in
00:23:35.120 that URL and that request is going to reach
00:23:41.880 the rail server and the sprocket ra we use the sprocket pipeline called the bug
00:23:50.400 to serve that asset that it was asked the the bug pip line was reged
00:23:58.000 like this is just array of processors and the only processor that you have in
00:24:04.240 that pipeline is the source map command processor this processor will generate a
00:24:10.440 asset bundler and in the end add a source map comand it is a comment like
00:24:16.679 this that is only pointing to the source map of that
00:24:21.720 file so to build the content of this F before adding the comment
00:24:28.480 is spets we use the default Pipeline and the default pipeline is
00:24:35.039 declared like this it's we take the type the file type of the file that is going
00:24:42.840 to be served and it's going to ask to this proess environment what is the default
00:24:50.080 processors for that type so this is implementation of the
00:24:55.200 default processor for is really is simple it's only takes the bundle
00:25:02.000 processor registered for that M type and if there is any processors registered
00:25:08.399 it's going to use that in example here
00:25:13.960 the bundle pipeline that's going to be used we just PR
00:25:20.799 compile all the required files in match then all together to compile each file
00:25:28.760 the self pipeline is going to be used the self pipeline is just the pipeline
00:25:33.799 that's get only one file and it's reg like
00:25:39.559 this it's pretty similar to the default and the implementation is also not so
00:25:45.760 complic complicated like it's get all the push processors of that type get all
00:25:52.480 that s to that type and later it get the prep processor process for that type in
00:25:59.840 the end it it adds the file reader processor that special kind of processors that reads the file from the
00:26:06.640 file system so to explain better I'm going to show uh image how that works so
00:26:14.880 we have the file read as the first processor later we have the C processor
00:26:20.600 and then the r directive processor so the file reader will read the file from
00:26:26.799 the file system and pass that data to the CCRI processor that's going to process the cscript code
00:26:35.039 and generate JavaScript code from that and later it's going to read out the
00:26:40.440 directives we have inside that asset and include include it in the metadata of
00:26:48.000 the asset so the processors always run in reverse order that they are
00:26:55.080 registered so first is the file reader later the cscript reader later the
00:27:01.240 directive processor after this is done for each individual file the BR processor will
00:27:08.559 measure of them and the result is going to be sent back to the browser so it's a
00:27:15.720 little bit complicated a lot of things have been done done in that single asset
00:27:24.799 request and you can imagine that this can be really slow in production so the
00:27:31.640 key difference between development and production is that in production all of
00:27:36.919 this happen in the prile test that we run in the deploy and only I st assets
00:27:44.159 is returned to your browser you don't need to do all this work every single
00:27:51.000 time now I'm going to sh show you how to extend these Pockets like one of the
00:27:56.679 things that we did in shopy was creating new directives in shopy we are using npm and
00:28:04.159 node modules to to be included in all Javas setup and
00:28:10.200 we created a new directive processor that's Define a npm directive so to
00:28:16.880 define a new directive you need to define a method that is called process
00:28:24.480 underscore something uncore directive and this I is the name of the directive
00:28:30.320 that is going to be used I'm not going to talk about the implementation of this
00:28:36.039 so after that's defined I can change my Thea directive processor with my new
00:28:44.640 directive processor that's in this case is my npm directive processor and I can use this new direct
00:28:52.240 directive in my JavaScript files now like when I saying that I need the low
00:28:58.240 Dash npm package I only use this new directive another way to extend these
00:29:04.799 Rockets is we also use that in shopy is sometimes we need to generate PNG image
00:29:13.760 from SVG because PG SVG does not work in
00:29:19.080 all the browsers so instead of doing that manually every single time that
00:29:25.000 someone's add a new SVG we have have a transform that does that automatically
00:29:30.200 for you at compile time so we register a transform from SVG to
00:29:36.519 PG and in my manif file I can say given
00:29:42.000 that I have a SVG file Al compile P version for
00:29:47.919 it and the implementation of this is really simple we are using the AR gen
00:29:55.360 just to read the data set the format to SPG
00:30:01.519 and later create the the result of that PG
00:30:10.600 image so this proess is used in many raos application out there it's inside
00:30:18.919 every single new application that's is generated but like we are right know here many users
00:30:26.840 don't know it's exist many users don't know how it works so it's important to everyone to
00:30:35.640 understand your tools to document your understanding this is what I doing here
00:30:53.480 you thank you rapael awesome uh so you know to deal with the questions you find
00:30:59.320 Rafael around the
00:31:16.760 stage