Question

When creating static apps I often start a new Rails app. This makes quite some things easier, like compilation (Coffeescript, SCSS), minimization (JS, CSS) and browser limitations (the page is being served from localhost:3000 so external sources can be loaded etc.).

At the end I want to export the app so I can put it online. Then I just need the HTML+CSS+JS. One can go and pluck the files out manually, but there probably is an easier way for this.

So: is there a tool that stores the compiled, minimized HTML+CSS+JS files from a Rails app?

Was it helpful?

Solution

If you just want to basically copy the website as it will be rendered by rails (and there is no need for server side code execution), you could just mirror the rails-website using

wget --page-requisites --convert-links http://URL-to-Start

However, this will only download those files that are referenced from the entry URL, so you might need to run it on all sub-URLs individually.

Source: Download a working local copy of a webpage

OTHER TIPS

Agree with Screenmutt. I've tried a couple of the ones mentioned but have had most success with:

http://middlemanapp.com/

Does pretty much everything you are asking for and let's you export to static HTML.

install:

gem install middleman

create project:

middleman init my_new_project (or even better with template --template=html5)

run in local server for live edits:

bundle exec middleman

dump static code:

bundle exec middleman build

Perhaps you can 'scrape' the HTML from the localhost serving it?

There seem to be some tools for downloading sites in general... You can probably limit them to download resources from localhost:3000 only.

UPDATE: Here's another tutorial that might help Use Rails 3.1 for Static Sites

This is not a common usage. You might be able to extract all the static pages by manually caching everything.

I would recommend taking a look at some alternatives.

I'm sorry that this isn't a good answer, but to be honest... You are using Rails for something that it was never intended to do. There are much better ways of making static sites.

Also, a static site is not an "app". :)

All you have to do is switch to Rails production mode locally so that assets are combined and minified. Then all you have to do is view source for the HTML, CSS, and JS. This should only take a few seconds.

So the steps are

  • config.assets.compress = true in development.rb
  • view the app locally
  • view source, copy and paste into an index.html file
  • click on compressed CSS and JS form source and save those relative to your index.html making sure they link correctly

You can use Wget (as it's already mentioned). I would go with:

wget --mirror --convert-links --adjust-extension --page-requisites --no-parent http://www.yourdomain.com

Yo can also use Httrack.

Be sure when you set Httrack you exclude all external websites with scripts so you don't download f.e. Google Analytics js files or Adsense or Facebook scripts. In Httrack, you exclude it in Preferences with:

-*.googlesyndication.com/* -*.facebook.net/* -*.google-analytics.com/*

After you are done you still need to rewrite all links because they will point at .../some-page/index.html You need .../some-page/. This solves Dynamic to Static Script.

You shouldn't serve them from rails or do anything that binds your static files to being served from rails. You may one day decide to serve your app from a CDN.

JS

One big tip would be to look at using AMD (async module definition), which would allow you to specify your JS file dependencies. Then you can use require.js and r.js(a tool that crawl and compile your dependencies in you precompile step). That would work for your JS.

CSS

For CSS, you could use sass or less. You'd include 1 file at the end of the day on your page, but the compilation process would involve merging your CSS files together. Once again this can be done at the pre-compile step.

CDN

There are gems out there that show take your assets and pass them over to something like S3, this answer and others like it would help: Is there a way to asset pipeline assets to s3 when pushing to heroku? ; however, that isn't necessary when you are first starting.

I did it with a Rake task that would fetch each of the Rails routes one at a time. It needed a bit of jiggery pokery to handle the fact that you might have conflicting routes - e.g. wget would fetch /objects as a file called "objects" but then when you want to fetch /objects/4 it would overwrite that file with a folder called "objects" with a nested file called "4". So I move each downloaded page to "index.html" inside a directory with the same name.

Here's my code, which I out in lib/tasks/export.rake:

def adjust_paths(path)
  text = File.read(path)
  new_contents = text.gsub(/("|\.\.\/)(assets|packs)\//, "\\1../\\2/")
  new_contents = new_contents.gsub("http://localhost:3020", "")
  File.write(path, new_contents)
end

namespace :static do
  desc 'Generate static site in ./out/ directory'
  task :export => [
      'assets:clean',
      'assets:precompile',
      :start_rails_server
  ] do

    begin
      out_prefix = "dist"

      paths = Rails.application.routes.routes.map do |route|
        route.path.spec.to_s
      end.uniq.reject { |p| p.starts_with?("/rails") || p == "/cable" || p == "/assets" }
      paths = paths.map { |p| p.sub("(.:format)", "") }

      paths.sort_by(&:length).each do |path|
        if path.include?(":id")
          # You'll have to use your own method for deciding which ids to use
          ids = ["1", "2", "3", "4"]
        else
          ids = [""]
        end
        ids.each do |id|
          id_path = path.sub(":id", id)
          `wget -P #{out_prefix} -nH -p -k http://localhost:3020#{id_path}`

          if id_path != "/"
            file_path = "#{out_prefix}#{id_path}"
            FileUtils.mv(file_path, "#{file_path}.tmp", force: true)
            FileUtils.mkdir_p(file_path)
            result = FileUtils.mv("#{file_path}.tmp", "#{file_path}/index.html", force: true)
            puts "Moving #{id_path} to #{id_path}/index.html: #{result}"

            # Will then need to relativise all of the asset paths, since we've moved it
            adjust_paths("#{file_path}/index.html")
          end

        end
      end

    ensure
      # stop the server when we're done
      Rake::Task['static:stop_rails_server'].reenable
      Rake::Task['static:stop_rails_server'].invoke
    end
  end

  desc 'Start a Rails server in the static Rails.env on port 3020'
  task :start_rails_server do
    `RAILS_SERVE_STATIC_FILES=1,RAILS_ENV=static rails s -p 3020 -d`
  end

  desc 'Stop Rails server'
  task :stop_rails_server do
    `cat tmp/pids/server.pid | xargs -I {} kill {}`
  end
end

Then you can just do bundle exec rake static:export

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top