How to build a Ruby on Rails Application with Vue.js using JSX

Have you ever wondered how many ways there are to build a Ruby on Rails application with VueJS?

This is the first of three articles which explain step by step how you can build a Rails application with VueJS with some advice on which technique you should use based on your needs.

Why JSX?

JSX is an extension of JavaScript. It can be used with VueJS to build components avoiding to use .vue templates.

With this approach, we can build a large and scalable frontend easily.

JSX syntax is recommended to integrate VueJS to an existing complex project or to start a project which needs a bold framework like Solidus.

Here are some of the advantages of using JSX:

  • The backend and frontend are in the same codebase
  • We can use the Rails routes (It isn’t a SPA)
  • We can share context between application sections (e.g., product page, sliding cart)
  • We can create many Vue instances for each section
  • We don’t necessarily have to build the APIs

And some of the disadvantages:

  • We can’t use .vue templates
  • With JSX Babel preset we can’t use some Vue directives like v-for, v-if, etc.

TL;DR;

You can find the code in this GitHub repository.

Branches:

  • master: Rails products catalog application without Webpack and VueJS
  • vuejs-jsx: integration of Webpack and VueJS on the Ruby on Rails application

Let’s start

We’ll start from an existing Rails application and will move it step by step to VueJS.

Clone the repository and bootstrap the project:

$ git clone https://github.com/vassalloandrea/rails-vuejs-jsx.git
$ cd rails-vuejs-jsx
$ asdf local ruby 2.5.1 # If you use asdf as version manager
$ ./bin/setup
$ bundle exec rails s

Project overview

The application is a products catalog.

The root path shows the list of the products and clicking on one of them reveals the product details. For each product you can read, add or delete the related comments.

Our goal is to move some parts of this app into VueJS components.

Start with the Vuetification

To run VueJS code in the Rails application, we need to install Webpack which is a static module bundler.

A Rails application is usually built with Sprockets to compile and serve web assets. Both libraries can live together.

Install Webpack using webpacker gem

  1. Add the webpacker gem into your Gemfile and install it
gem 'webpacker', '~> 4.x'$ bundle install
$ bundle exec rails webpacker:install

The installation command generates all the files needed to configure Webpack on Rails.

To manage all the JS dependencies we use yarn. Install Node using your favorite version manager, I usually use asdf

$ asdf install nodejs 10.16.0
$ asdf local nodejs 10.16.0

and install yarn

$ npm i -g yarn@1.16.0

To check if the project is now working with Webpack, restart the Rails server and the webpack-dev-server

$ yarn install
$ bundle exec rails server
$ ./bin/webpack-dev-server 

2. Now add the pack link in your application.html.erb file

<head>
        <title>RailsVuejsJsx</title>
        <%= csrf_meta_tags %>
        <%= csp_meta_tag %>

        <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

        <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>

3. If everything is set in the correct way, you should see the Webpacker message in the browser console

How to build a Ruby on Rails Application with Vue.js using JSX

Install VueJS

1. Install VueJS using the Webpacker command:

$ bundle exec rails webpacker:install:vue

2. Remove useless files like: hello_vue.js and app.vue

3. If your project uses Turbolinks, install the vue-turbolinks library

$ yarn add vue-turbolinks

4. Edit the application.js file, pay attention here: we MUST change theapplication.js in the javascript/packs directory of the app

    /* eslint no-console:0 */

    import TurbolinksAdapter from 'vue-turbolinks'
    import Vue from 'vue'

    // Import all the macro components of the application
    import * as instances from '../instances'

    Vue.use(TurbolinksAdapter)

    document.addEventListener('turbolinks:load', () => {
        // Initialize available instances
        Object.keys(instances).forEach((instanceName) => {
            const instance = instances[instanceName]
            const elements = document.querySelectorAll(instance.el)

            elements.forEach((element) => {
              const props = JSON.parse(element.getAttribute('data-props'))

              new Vue({
                el: element,
                render: h => h(instance.component, { props })
              })
            })
        })
    })

5. Create the instances.js file which contains all the Vue instances, the application macro-areas that you want to migrate to Vue

app/javascript/instances.js

   // Import components
    import ProductList from './components/product/index'

    export const ProductListInstance = {
        el: '.vue-products',
        component: ProductList
    }

6. Add your first Vue component app/javascript/components/product/index.js that shows the product list

export default {
    name: 'ProductList',

    render() {
        return(
            <h1>Products catalog</h1>
        )
    }
}

7. Replace the content of app/views/products/index.html.erb:

<div class="vue-products"></div>

If you restart the Rails and Webpack server, you should see an error:

How to build a Ruby on Rails Application with Vue.js using JSX

The problem is that Babel doesn’t have the correct preset to understand the JSX syntax with VueJS. To solve the issue, we must add the preset and configure Babel to use it.

$ yarn add @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props

Open the Babel configuration file babel.config.js and add the preset to the presets array. At the end it should look like this:

    presets: [
        isTestEnv && [
            require('@babel/preset-env').default,
            {
              targets: {
                node: 'current'
              }
            }
        ],
          (isProductionEnv || isDevelopmentEnv) && [
            require('@babel/preset-env').default,
            {
              forceAllTransforms: true,
              useBuiltIns: 'entry',
              corejs: 3,
              modules: false,
              exclude: ['transform-typeof-symbol']
            }
        ],
        '@vue/babel-preset-jsx'
    ].filter(Boolean)

If you restart the Webpack server and reload the page, you should see your first component.

How to build a Ruby on Rails Application with Vue.js using JSX

Move the product list to VueJS

The fastest way to do this should be to copy the html.erb template in the component file and replace the ERB code with JSX.

In this example, I copied the content of app/views/products/index.html.erb to app/javascript/components/product/index.js and deleted the Rails code.

When you build a VueJS application, it’s very important to create a component for every piece of code that has a different context. For example: product/index.js will show the list of products but each product should be a separated component called product/card.js.

Here are the results:

  • app/javascript/components/product/index.js
    import ProductCard from './card'

    export default {
        name: 'ProductList',

        props: {
        products: Array
        },

        render() {
            return(
              <div>
                <h1 class="my-4">
                  Products catalog
                </h1>

                <div class="row">
                  {this.products.map(product => (
                    <ProductCard product={product} />
                  ))}
                </div>
              </div>
            )
        }
    }
  • app/javascript/components/product/card.js
 export default {
        name: 'ProductCard',

        props: {
            product: Object
        },

        methods: {
            shortDescription() {
              let description = this.product.description
              if (description.length > 50) {
                return `${description.substr(0, 50)}...`
              } else {
                return description
              }
            }
        },

        render() {
            return(
              <div class="col-lg-4 col-sm-6 mb-4">
                <div class="card h-100">
                  <a href={this.product.url}>
                    <img src={this.product.image} class="card-img-top" alt="" />
                  </a>
                  <div class="card-body">
                    <h4 class="card-title">
                      <a href={this.product.url}>
                        { this.product.name }
                      </a>
                    </h4>
                    <p class="card-text">
                      { this.shortDescription() }
                    </p>
                  </div>
                </div>
              </div>
            )
        }
    }
  • The product list component has to render the products which should be passed using props. props is a JS object which contains the params passed by the parent component. In this example, you have to pass the products to the ProductCard component when you render it.
  • app/views/products/index.html.erb
   <% props = { products: serialize('serializers/products', products: @products) }.to_json %>

    <div class="vue-products" data-props="<%= props %>"></div>
  • The serialize method is a helper method which you must add to app/helpers/application_helper.rb
    module ApplicationHelper
        def serialize(template, options = {})
            JbuilderTemplate
              .new(self) { |json| json.partial! template, options }.attributes!
        end
    end
  • Product list serializer: app/views/serializers/_products.jbuilder
   json.array! products do |product|
        json.partial! 'serializers/product', product: product
    end
  • Product detail serializer: app/views/serializers/_product.jbuilder
    json.id product.id
    json.name product.name
    json.description product.description
    json.image url_for(product.image)
    json.url product_path(product)

Now the product list page should work showing the list of the products using VueJS.

How to build a Ruby on Rails Application with Vue.js using JSX

Add Vuex to manage the application state

Vuex is a VueJS library that enables us to share the state of the application between all the Vue instances and components that use it.

If you want to pass some data from a parent to a child you could use props and the state is not needed, but what happens if a sibling component changes some data that is showed from another component?

Vuex resolves this problem centralizing the application data.

A Vuex instance, usually called store, could have many modules. Each module is a JS object which has a state, some actions, mutations and getters.

  • State: contains the JS objects initialization that should be shared between Vue instances. It can’t be modified directly from a component.
  • Actions: methods called from a component that act as a middleware between the components and the state of the application. For example, if a component wants to delete a comment, the actions should call the APIs to accomplish the request and commit the changes calling the correct mutation based on the response.
  • Mutations: list of methods that change the state of the store/application.

Install vuex

$ yarn add vuex

Configure the store: a little bit of boilerplate

  • Create the app/javascript/store/index.js file which creates the Vuex instance
    import Vue from 'vue'
    import Vuex from 'vuex'

    import modules from './modules'

    Vue.use(Vuex)

    export default new Vuex.Store({
      modules,
      strict: process.env.NODE_ENV !== 'production'
    })
  • Create the app/javascript/store/modules/index.js file which includes all the store modules
    import product from './product'
  
    export default {
        product
    }
  • Create the modules. In this case, the store should store only the product comments app/javascript/store/modules/product.js
    const defaultState = {
        comments: []
    }

    export const actions = {
        fillComments({ commit }, comments) {
            commit('fillComments', comments)
        }
    }

    export const mutations = {
        fillComments(state, comments) {
            state.comments = comments
        }
    }

    export default {
        state: defaultState,
        actions,
        mutations
    }
  • Add the store instance to the VueJS instances in the app/javascript/packs/application.js file like this
    ...
    ...

    // Import the store
    import store from '../store'

    ...
    ...
    ...

        new Vue({
            el: element,
            store,
            render: h => h(instance.component, { props })
        })

Install and configure i18n-js gem

This is used to share translations between Rails and Javascript.

  • Add the i18n-js gem to the Gemfile
  • Run bundle install
  • Add the //= require i18n/translations into the app/assets/javascripts/application.js file
  • Restart the server

Move the comments list to VueJS

As initially said, we can move the whole application to VueJS or only some of its sections. In this case, we are moving the product list, the comments list and the comment form.

  • Add the comments list component to app/javascript/instances.js
    // Import components
    import ProductList from './components/product/index'
    import CommentList from './components/comment/index'

    export const ProductListInstance = {
        el: '.vue-products',
        component: ProductList
    }

    export const CommentListInstance = {
        el: '.vue-comments',
        component: CommentList
    }
  • Comments list component: app/javascript/components/comment/index.js
    import { mapState, mapActions } from 'vuex'

    import CommentCard from './card'

    export default {
        name: 'CommentList',

        props: {
            product: Object
        },

        computed: {
            ...mapState({
              comments: state => state.product.comments
            })
        },

        methods: {
            ...mapActions({
              fillComments: 'fillComments'
            }),
            thereAreComments() {
              return this.comments.length > 0
            }
        },

        mounted() {
            this.fillComments(this.product.comments)
        },

        render() {
            return(
              <div>
                <h4 class="my-4">Comments</h4>

                <div class="row">
                  {this.thereAreComments() &&
                    this.comments.map(comment => (
                      <CommentCard comment={comment} />
                    ))
                  }

                  {!this.thereAreComments() &&
                    <div class="col-md-12">
                      <p>
                        { I18n.t('comments.empty') }
                      </p>
                    </div>
                  }
                </div>
              </div>
            )
        }
    }
  • Comment card component: app/javascript/components/comment/card.js
    import { mapActions } from 'vuex'

    export default {
        name: 'CommentCard',

        props: {
            comment: Object
        },

        methods: {
            ...mapActions({
              cancelComment: 'cancelComment'
            })
        },

        render() {
            return(
              <div class="col-md-12 my-2">
                <div class="card">
                  <div class="card-body">
                    <h5 class="card-title">{ this.comment.title }</h5>
                    <p class="card-text">{ this.comment.description }</p>

                    <button class="btn btn-sm btn-danger" onClick={event => this.cancelComment(this.comment.id)}>
                      { I18n.t('comments.form.delete') }
                    </button>
                  </div>
                </div>
              </div>
            )
        }
    }
  • Remove the comments partial: app/views/shared/_comments.html.erb
  • Replace the content of app/views/products/show.html.erb with this:
    <h1 class="my-4">
        <%= @product.name %>
    </h1>
    <p>
        <%= link_to t('products.back'), products_path %>
    </p>

    <div class="row">
        <div class="col-md-8">
            <%= image_tag @product.image, class: 'img-fluid' %>
        </div>

        <div class="col-md-4">
            <h3 class="my-3">Project Description</h3>
            <p>
              <%= @product.description %>
            </p>
        </div>
    </div>

    <%
        props = {
            product: serialize('serializers/product', product: @product)
        }.to_json
    %>

    <div class="vue-comments" data-props="<%= props %>"></div>
  • Add the comment serializer at the end of app/views/serializers/_product.jbuilder:
    json.comments product.comments do |comment|
        json.partial! 'serializers/comment', comment: comment
    end
  • Create the comment serializer app/views/serializers/_comment.jbuilder:
    json.id comment.id
    json.title comment.title
    json.description comment.description
  • Create a couple of comments using the console:
$ bundle exec rails console    product = Product.first
    Comment.create!(title: 'This is the first comment', description: 'Comment description', product: product)
    Comment.create!(title: 'This is the second comment', description: 'Comment description', product: product)

At this point, you should see the page like before with the comment list. However, the delete comment button doesn’t work. This happens because the action deleteComment wasn’t implemented into the store.

How to build a Ruby on Rails Application with Vue.js using JSX

Install Axios to make HTTP requests

To add or delete a comment without reloading the product page, we must implement the APIs and consume them using the Axios library.

$ yarn add axios

Implement the APIs to create and delete a comment

  1. Change the config/routes.rb file
    Rails.application.routes.draw do
        root 'products#index'

        resources :products, only: %i[index show]

        namespace :api do
            resources :comments, only: :destroy

            resources :products, only: [] do
              resources :comments, only: :create
            end
        end
    end

2. Remove app/controllers/comments_controller.rb

3. Create the API comments controller app/controllers/api/comments_controller.rb

4. Implement the create and destroy methods

    Rails.application.routes.draw do
        root 'products#index'

        resources :products, only: %i[index show]

        namespace :api do
            resources :comments, only: :destroy

            resources :products, only: [] do
              resources :comments, only: :create
            end
        end
    end

Delete the comments

To recap, we added a button to delete a comment to the comment card component.

When the user clicks on the delete button, the component should dispatch the correct action, e.g. deleteComment.

The action calls the correct API method (which doesn’t exist yet) and it will commit the correct mutation based on the response.

If the destroy API call was successful, remove the deleted comment from the comments array.

If the destroy API call was unsuccessful, fill the errors array to show the errors.

Implement the API client with Axios

  1. Create the Axios instance app/javascript/api/instance.js
    import axios from 'axios'

    axios.defaults.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')

    export default axios.create()

2. Add the index file app/javascript/api/index.js which exports all the API modules. In this case, we use Axios only to manage the comments.

   import comment from './comment'

    export default {
        comment
    }

3. Implement the methods that will make the HTTP request: app/javascript/api/comment.js

    import api from './instance'

    /**
    * Create a comment
    */
    const create = (productId, commentParams) => (
        api.post(Routes.api_product_comments_path(productId), commentParams)
        .then(response => response.data)
    )

    /**
    * Destroy a comment
    */
    const destroy = (commentId) => (
        api.delete(Routes.api_comment_path(commentId))
        .then(response => response.data)
    )

    export default {
        create,
        destroy
    }

Install and configure js-routes gem

This gem is needed to share Rails routes with JavaScript.

  1. Add the gem to the Gemfile and run bundle install:
gem ‘js-routes’

2. Require the gem in app/assets/javascripts/application.js:

//= require js-routes

3. Configure js-routes specifying which routes should be shared by creating the configuration file: config/initializers/js_routes.rb

    # frozen_string_literal: true

    JsRoutes.setup do |config|
        config.include = [
            /^api_comment$/,
            /^api_product_comments$/,
        ]
    end

4. Run this commands and restart the Rails server:

$ bundle exec rails tmp:cache:clear

Implement the action and the mutations

  1. Import the API module in the product store app/javascript/store/modules/product.js
import api from '../../api'

2. Add the method to the actions object:

     cancelComment({ commit }, commentId) {
        api.comment.destroy(commentId)
          .then(() => {
            commit('commentCancelled', commentId)
          })
      }

3. Add the method commentCancelled to the mutation object:

    commentCancelled(state, commentId) {
        state.comments = state.comments.filter(comment => commentId !== comment.id)
    },

The commentCancelled method will filter the comments array removing the canceled comment.

At this point, the delete comment feature should work.

How to build a Ruby on Rails Application with Vue.js using JSX

Add a comment

Since we removed the comment form partial from the product show view, the form disappeared from the page. To fix this, we will create the commentForm Vue component.

  1. Create the component: app/javascript/components/comment/form.js
    import { mapActions } from 'vuex'

    export default {
        props: {
            product: Object
        },

        data() {
            return {
              title: '',
              description: ''
            }
        },

        methods: {
            ...mapActions({
              addComment: 'addComment'
            }),
            submitComment() {
              this.addComment({
                productId: this.product.id,
                commentParams: {
                  title: this.title,
                  description: this.description
                }
              })

              this.title = ''
              this.description = ''
            }
        },

        render() {
            return(
              <div class="row my-2">
                <div class="col-md-8">
                  <h4 class="my-4">Add new comment</h4>

                  <div class="form-label-group">
                    <input type="input" class="form-control" name="title"
                      placeholder={I18n.t('comments.form.title')}
                      autofocus="true" vModel_trim={this.title} />
                  </div>

                  <div class="form-label-group my-3">
                    <input type="input" class="form-control" name="description"
                      placeholder={I18n.t('comments.form.description')}
                      vModel_trim={this.description} />
                  </div>

                  <input type="submit" class="btn btn-primary" value={I18n.t('comments.form.submit')}
                    vOn:click_stop_prevent={this.submitComment} />
                </div>
              </div>
            )
        }
    }

2. Add the component to the instances file: app/javascript/instances.js

    // Import components
    import ProductList from './components/product/index'
    import CommentList from './components/comment/index'
    import CommentForm from './components/comment/form'

    export const ProductListInstance = {
        el: '.vue-products',
        component: ProductList
    }

    export const CommentListInstance = {
        el: '.vue-comments',
        component: CommentList
    }

    export const CommentFormInstance = {
        el: '.vue-comment-form',
        component: CommentForm
    }

3. Add the commentForm wrapper at the end of the product show: app/views/products/show.html.erb

    <div class="vue-comment-form" data-props="<%= props %>">
    </div>

Now, the comment form appears at the end of the product detail page again, but it doesn’t work.

  1. Add the addComment action that calls the create method of the APIs in app/javascript/store/modules/product.js
    addComment({ commit }, { productId, commentParams }) {
        api.comment.create(productId, commentParams)
          .then((comment) => {
            commit('commentAdded', comment)
          })
    }

2. Add the commentAdded mutation which updates the comments array in app/javascript/store/modules/product.js

    commentAdded(state, comment) {
        state.comments.push(comment)
    }

Finally we’re done

Now your application uses both Rails and VueJS to render views and components. To learn how to manage errors with the comment form, you can use the repository linked above.

#vue-js #ruby-on-rails #web-development

What is GEEK

Buddha Community

How to build a Ruby on Rails Application with Vue.js using JSX
Shardul Bhatt

Shardul Bhatt

1618576835

Why should we use Ruby on Rails for Software Development?

What is Rails, Ruby on Rails?

Rails is a server-side web application development framework written in the Ruby programming language. Its emergence in 2005 has influenced and impacted web application development to a vast range, including but not limited to seamless database tables, migrations, and scaffolding of views. In the simplest understanding, Rails is a highly productive and intuitive software developer. 

Websites and applications of any complexity can be achieved with Ruby on Rails. The software is designed to perceive the needs of ruby on rails developers and encourage them with the best way out. It is designed to allow developers to write lesser code while spiking productivity much more than any other framework or language. Ruby on Rails rapid application development offers everyday web development tasks easier and uniquely out-of-the-box, both with the same effectiveness.

The Ruby on Rails framework is based on two philosophies:

 

  • Don’t Repeat Yourself (DRY): It is a software development principle that ensures that every piece or entity of knowledge must be assigned with a single and unambiguous representation within a development system.

    It not only reduces the need to write lengthy codes but also eliminates the repetitive writing of codes. As a result, it provides a much more manageable web app development with the least possible bugs.

 

  • Convention over Configuration (CoC): It indicates the highly opinionated feature that the Ruby on Rails framework possesses. It offers ready-made solutions or the “best way out” for many tasks in a web application and defaults them to the convention without the need for external specification. The programmer using the software is required to specify only the unconventional aspects of the web application. 

Some of the commonly known websites built by the Ruby on Rails software developers are Instacart, Scribd, Shopify, Github, ConvertKit, Soundcloud, GoodReads, Airbnb. It finds its application in Sa-as Solutions, Social Networking Platforms, Dating websites, Stock Exchange Platforms, etc.  

Read more: Why Ruby on Rails is Perfect for eCommerce Web Development

Why use Ruby on Rails: The multifold benefits

  • Community and its abundant resources 

    • There is a large community that is dedicated to Ruby on Rails that keeps it up-to-date and indeed encourages its family of developers to continue using it. They make sure the benefits are soaring with every update they make. 

    • The community is committed to developing several ready-to-use code packages, commonly known as gems, for its users. They discuss and announce new project launches, help each other with queries, and engage in framework discussions and betterment. While Ruby on Rails helps developers in rapid application development, it also connects and grows businesses together.

  • Project Scalability

    • To talk about scalability, we indicate the ability to grow and manage more and more user requests per minute (RPM). However, this depends on the architecture rather than the framework. The right architecture of Ruby on Rails web application development allows it to write bulky codes and programs as compared to early-stage difficulties with scalability. 

    • It uses the Representational State Transfer (REST) architecture. This will enable Rails to create efficient web applications based on Rails 6, launched last year in 2020, which addresses most scalability issues. The portable components are agile and help in a better understanding of new requirements and needful adaptations for any business. The framework and architecture allow both vertical and horizontal scalability.

  • Fast Application Development and Cost Effectiveness

    • Ruby on Rails is lucid, logical, and has lean code requirements, thereby cutting down redundancy and improving the overall development speed. Lesser amount of code is proportional to lesser time investment with optimal results. The more time it takes for development, the more expensive it becomes for the end customers.

    • Considering the ready-made code modules/packages (gems) available, Ruby on Rails development company will less time and money are spent creating and modifying Rails websites and applications. Another advantage that has made Ruby on Rails super attractive for startups is its use of Model-View-Controller (MVC) architecture. It has a component separation scheme that speeds up the web development process and fixes any errors that occur.  

  • Data Protection

    • Rails framework and the Ruby on Rails community put in a lot of efforts for data protection and security of its customer base. It is also one of the efficient frameworks for developing database-backed applications. 

    • The developers at Ruby on Rails cover many aspects of cybersecurity, including encryptions of  passwords, credit card information, and users’ personal database. Special measures are taken to prevent the framework from SQL injections and XSS attacks. 

  • Ruby on Rails Enterprise Application Development

    • Ruby on Rails simplifies the daily operations and lowers the cost of enterprise app developments. The prominent features include data management, seamless updating of applications, easy and efficient code development, and high scalability, as discussed above. 

    • Ruby on Rails enterprise application development is preferred by companies and is slightly cost-intensive. It can be easily integrated with third-party apps like Oracle Business, Oracle, Windows services, and others. Ruby enterprise app development allows the developers and programmers to solve the problems at the root level, given its transparency.

Ruby on Rails V/S Django

Checkout Blog on Django vs Ruby on Rails Comparison

Bottom Line

There are several reasons to prefer Ruby on Rails discussed above and extend further to early detection of errors, reduced time to market, and easy adaptation for API developments. It makes web programming much easier and simplifies website building of any complexity. Its flexibility and acceptance among new developers and programmers make it the perfect, one-stop choice for software application development company in 2021. 

Source: https://techsite.io/p/2121044

#ruby on rails examples #ruby on rails rapid application development #ruby on rails web application development #ruby on rails software developer #ruby on rails enterprise application development

Chloe  Butler

Chloe Butler

1667425440

Pdf2gerb: Perl Script Converts PDF Files to Gerber format

pdf2gerb

Perl script converts PDF files to Gerber format

Pdf2Gerb generates Gerber 274X photoplotting and Excellon drill files from PDFs of a PCB. Up to three PDFs are used: the top copper layer, the bottom copper layer (for 2-sided PCBs), and an optional silk screen layer. The PDFs can be created directly from any PDF drawing software, or a PDF print driver can be used to capture the Print output if the drawing software does not directly support output to PDF.

The general workflow is as follows:

  1. Design the PCB using your favorite CAD or drawing software.
  2. Print the top and bottom copper and top silk screen layers to a PDF file.
  3. Run Pdf2Gerb on the PDFs to create Gerber and Excellon files.
  4. Use a Gerber viewer to double-check the output against the original PCB design.
  5. Make adjustments as needed.
  6. Submit the files to a PCB manufacturer.

Please note that Pdf2Gerb does NOT perform DRC (Design Rule Checks), as these will vary according to individual PCB manufacturer conventions and capabilities. Also note that Pdf2Gerb is not perfect, so the output files must always be checked before submitting them. As of version 1.6, Pdf2Gerb supports most PCB elements, such as round and square pads, round holes, traces, SMD pads, ground planes, no-fill areas, and panelization. However, because it interprets the graphical output of a Print function, there are limitations in what it can recognize (or there may be bugs).

See docs/Pdf2Gerb.pdf for install/setup, config, usage, and other info.


pdf2gerb_cfg.pm

#Pdf2Gerb config settings:
#Put this file in same folder/directory as pdf2gerb.pl itself (global settings),
#or copy to another folder/directory with PDFs if you want PCB-specific settings.
#There is only one user of this file, so we don't need a custom package or namespace.
#NOTE: all constants defined in here will be added to main namespace.
#package pdf2gerb_cfg;

use strict; #trap undef vars (easier debug)
use warnings; #other useful info (easier debug)


##############################################################################################
#configurable settings:
#change values here instead of in main pfg2gerb.pl file

use constant WANT_COLORS => ($^O !~ m/Win/); #ANSI colors no worky on Windows? this must be set < first DebugPrint() call

#just a little warning; set realistic expectations:
#DebugPrint("${\(CYAN)}Pdf2Gerb.pl ${\(VERSION)}, $^O O/S\n${\(YELLOW)}${\(BOLD)}${\(ITALIC)}This is EXPERIMENTAL software.  \nGerber files MAY CONTAIN ERRORS.  Please CHECK them before fabrication!${\(RESET)}", 0); #if WANT_DEBUG

use constant METRIC => FALSE; #set to TRUE for metric units (only affect final numbers in output files, not internal arithmetic)
use constant APERTURE_LIMIT => 0; #34; #max #apertures to use; generate warnings if too many apertures are used (0 to not check)
use constant DRILL_FMT => '2.4'; #'2.3'; #'2.4' is the default for PCB fab; change to '2.3' for CNC

use constant WANT_DEBUG => 0; #10; #level of debug wanted; higher == more, lower == less, 0 == none
use constant GERBER_DEBUG => 0; #level of debug to include in Gerber file; DON'T USE FOR FABRICATION
use constant WANT_STREAMS => FALSE; #TRUE; #save decompressed streams to files (for debug)
use constant WANT_ALLINPUT => FALSE; #TRUE; #save entire input stream (for debug ONLY)

#DebugPrint(sprintf("${\(CYAN)}DEBUG: stdout %d, gerber %d, want streams? %d, all input? %d, O/S: $^O, Perl: $]${\(RESET)}\n", WANT_DEBUG, GERBER_DEBUG, WANT_STREAMS, WANT_ALLINPUT), 1);
#DebugPrint(sprintf("max int = %d, min int = %d\n", MAXINT, MININT), 1); 

#define standard trace and pad sizes to reduce scaling or PDF rendering errors:
#This avoids weird aperture settings and replaces them with more standardized values.
#(I'm not sure how photoplotters handle strange sizes).
#Fewer choices here gives more accurate mapping in the final Gerber files.
#units are in inches
use constant TOOL_SIZES => #add more as desired
(
#round or square pads (> 0) and drills (< 0):
    .010, -.001,  #tiny pads for SMD; dummy drill size (too small for practical use, but needed so StandardTool will use this entry)
    .031, -.014,  #used for vias
    .041, -.020,  #smallest non-filled plated hole
    .051, -.025,
    .056, -.029,  #useful for IC pins
    .070, -.033,
    .075, -.040,  #heavier leads
#    .090, -.043,  #NOTE: 600 dpi is not high enough resolution to reliably distinguish between .043" and .046", so choose 1 of the 2 here
    .100, -.046,
    .115, -.052,
    .130, -.061,
    .140, -.067,
    .150, -.079,
    .175, -.088,
    .190, -.093,
    .200, -.100,
    .220, -.110,
    .160, -.125,  #useful for mounting holes
#some additional pad sizes without holes (repeat a previous hole size if you just want the pad size):
    .090, -.040,  #want a .090 pad option, but use dummy hole size
    .065, -.040, #.065 x .065 rect pad
    .035, -.040, #.035 x .065 rect pad
#traces:
    .001,  #too thin for real traces; use only for board outlines
    .006,  #minimum real trace width; mainly used for text
    .008,  #mainly used for mid-sized text, not traces
    .010,  #minimum recommended trace width for low-current signals
    .012,
    .015,  #moderate low-voltage current
    .020,  #heavier trace for power, ground (even if a lighter one is adequate)
    .025,
    .030,  #heavy-current traces; be careful with these ones!
    .040,
    .050,
    .060,
    .080,
    .100,
    .120,
);
#Areas larger than the values below will be filled with parallel lines:
#This cuts down on the number of aperture sizes used.
#Set to 0 to always use an aperture or drill, regardless of size.
use constant { MAX_APERTURE => max((TOOL_SIZES)) + .004, MAX_DRILL => -min((TOOL_SIZES)) + .004 }; #max aperture and drill sizes (plus a little tolerance)
#DebugPrint(sprintf("using %d standard tool sizes: %s, max aper %.3f, max drill %.3f\n", scalar((TOOL_SIZES)), join(", ", (TOOL_SIZES)), MAX_APERTURE, MAX_DRILL), 1);

#NOTE: Compare the PDF to the original CAD file to check the accuracy of the PDF rendering and parsing!
#for example, the CAD software I used generated the following circles for holes:
#CAD hole size:   parsed PDF diameter:      error:
#  .014                .016                +.002
#  .020                .02267              +.00267
#  .025                .026                +.001
#  .029                .03167              +.00267
#  .033                .036                +.003
#  .040                .04267              +.00267
#This was usually ~ .002" - .003" too big compared to the hole as displayed in the CAD software.
#To compensate for PDF rendering errors (either during CAD Print function or PDF parsing logic), adjust the values below as needed.
#units are pixels; for example, a value of 2.4 at 600 dpi = .0004 inch, 2 at 600 dpi = .0033"
use constant
{
    HOLE_ADJUST => -0.004 * 600, #-2.6, #holes seemed to be slightly oversized (by .002" - .004"), so shrink them a little
    RNDPAD_ADJUST => -0.003 * 600, #-2, #-2.4, #round pads seemed to be slightly oversized, so shrink them a little
    SQRPAD_ADJUST => +0.001 * 600, #+.5, #square pads are sometimes too small by .00067, so bump them up a little
    RECTPAD_ADJUST => 0, #(pixels) rectangular pads seem to be okay? (not tested much)
    TRACE_ADJUST => 0, #(pixels) traces seemed to be okay?
    REDUCE_TOLERANCE => .001, #(inches) allow this much variation when reducing circles and rects
};

#Also, my CAD's Print function or the PDF print driver I used was a little off for circles, so define some additional adjustment values here:
#Values are added to X/Y coordinates; units are pixels; for example, a value of 1 at 600 dpi would be ~= .002 inch
use constant
{
    CIRCLE_ADJUST_MINX => 0,
    CIRCLE_ADJUST_MINY => -0.001 * 600, #-1, #circles were a little too high, so nudge them a little lower
    CIRCLE_ADJUST_MAXX => +0.001 * 600, #+1, #circles were a little too far to the left, so nudge them a little to the right
    CIRCLE_ADJUST_MAXY => 0,
    SUBST_CIRCLE_CLIPRECT => FALSE, #generate circle and substitute for clip rects (to compensate for the way some CAD software draws circles)
    WANT_CLIPRECT => TRUE, #FALSE, #AI doesn't need clip rect at all? should be on normally?
    RECT_COMPLETION => FALSE, #TRUE, #fill in 4th side of rect when 3 sides found
};

#allow .012 clearance around pads for solder mask:
#This value effectively adjusts pad sizes in the TOOL_SIZES list above (only for solder mask layers).
use constant SOLDER_MARGIN => +.012; #units are inches

#line join/cap styles:
use constant
{
    CAP_NONE => 0, #butt (none); line is exact length
    CAP_ROUND => 1, #round cap/join; line overhangs by a semi-circle at either end
    CAP_SQUARE => 2, #square cap/join; line overhangs by a half square on either end
    CAP_OVERRIDE => FALSE, #cap style overrides drawing logic
};
    
#number of elements in each shape type:
use constant
{
    RECT_SHAPELEN => 6, #x0, y0, x1, y1, count, "rect" (start, end corners)
    LINE_SHAPELEN => 6, #x0, y0, x1, y1, count, "line" (line seg)
    CURVE_SHAPELEN => 10, #xstart, ystart, x0, y0, x1, y1, xend, yend, count, "curve" (bezier 2 points)
    CIRCLE_SHAPELEN => 5, #x, y, 5, count, "circle" (center + radius)
};
#const my %SHAPELEN =
#Readonly my %SHAPELEN =>
our %SHAPELEN =
(
    rect => RECT_SHAPELEN,
    line => LINE_SHAPELEN,
    curve => CURVE_SHAPELEN,
    circle => CIRCLE_SHAPELEN,
);

#panelization:
#This will repeat the entire body the number of times indicated along the X or Y axes (files grow accordingly).
#Display elements that overhang PCB boundary can be squashed or left as-is (typically text or other silk screen markings).
#Set "overhangs" TRUE to allow overhangs, FALSE to truncate them.
#xpad and ypad allow margins to be added around outer edge of panelized PCB.
use constant PANELIZE => {'x' => 1, 'y' => 1, 'xpad' => 0, 'ypad' => 0, 'overhangs' => TRUE}; #number of times to repeat in X and Y directions

# Set this to 1 if you need TurboCAD support.
#$turboCAD = FALSE; #is this still needed as an option?

#CIRCAD pad generation uses an appropriate aperture, then moves it (stroke) "a little" - we use this to find pads and distinguish them from PCB holes. 
use constant PAD_STROKE => 0.3; #0.0005 * 600; #units are pixels
#convert very short traces to pads or holes:
use constant TRACE_MINLEN => .001; #units are inches
#use constant ALWAYS_XY => TRUE; #FALSE; #force XY even if X or Y doesn't change; NOTE: needs to be TRUE for all pads to show in FlatCAM and ViewPlot
use constant REMOVE_POLARITY => FALSE; #TRUE; #set to remove subtractive (negative) polarity; NOTE: must be FALSE for ground planes

#PDF uses "points", each point = 1/72 inch
#combined with a PDF scale factor of .12, this gives 600 dpi resolution (1/72 * .12 = 600 dpi)
use constant INCHES_PER_POINT => 1/72; #0.0138888889; #multiply point-size by this to get inches

# The precision used when computing a bezier curve. Higher numbers are more precise but slower (and generate larger files).
#$bezierPrecision = 100;
use constant BEZIER_PRECISION => 36; #100; #use const; reduced for faster rendering (mainly used for silk screen and thermal pads)

# Ground planes and silk screen or larger copper rectangles or circles are filled line-by-line using this resolution.
use constant FILL_WIDTH => .01; #fill at most 0.01 inch at a time

# The max number of characters to read into memory
use constant MAX_BYTES => 10 * M; #bumped up to 10 MB, use const

use constant DUP_DRILL1 => TRUE; #FALSE; #kludge: ViewPlot doesn't load drill files that are too small so duplicate first tool

my $runtime = time(); #Time::HiRes::gettimeofday(); #measure my execution time

print STDERR "Loaded config settings from '${\(__FILE__)}'.\n";
1; #last value must be truthful to indicate successful load


#############################################################################################
#junk/experiment:

#use Package::Constants;
#use Exporter qw(import); #https://perldoc.perl.org/Exporter.html

#my $caller = "pdf2gerb::";

#sub cfg
#{
#    my $proto = shift;
#    my $class = ref($proto) || $proto;
#    my $settings =
#    {
#        $WANT_DEBUG => 990, #10; #level of debug wanted; higher == more, lower == less, 0 == none
#    };
#    bless($settings, $class);
#    return $settings;
#}

#use constant HELLO => "hi there2"; #"main::HELLO" => "hi there";
#use constant GOODBYE => 14; #"main::GOODBYE" => 12;

#print STDERR "read cfg file\n";

#our @EXPORT_OK = Package::Constants->list(__PACKAGE__); #https://www.perlmonks.org/?node_id=1072691; NOTE: "_OK" skips short/common names

#print STDERR scalar(@EXPORT_OK) . " consts exported:\n";
#foreach(@EXPORT_OK) { print STDERR "$_\n"; }
#my $val = main::thing("xyz");
#print STDERR "caller gave me $val\n";
#foreach my $arg (@ARGV) { print STDERR "arg $arg\n"; }

Download Details:

Author: swannman
Source Code: https://github.com/swannman/pdf2gerb

License: GPL-3.0 license

#perl 

Ruby on Rails Development Services | Ruby on Rails Development

Ruby on Rails is a development tool that offers Web & Mobile App Developers a structure for all the codes they write resulting in time-saving with all the common repetitive tasks during the development stage.

Want to build a Website or Mobile App with Ruby on Rails Framework

Connect with WebClues Infotech, the top Web & Mobile App development company that has served more than 600 clients worldwide. After serving them with our services WebClues Infotech is ready to serve you in fulfilling your Web & Mobile App Development Requirements.

Want to know more about development on the Ruby on Rails framework?

Visit: https://www.webcluesinfotech.com/ruby-on-rails-development/

Share your requirements https://www.webcluesinfotech.com/contact-us/

View Portfolio https://www.webcluesinfotech.com/portfolio/

#ruby on rails development services #ruby on rails development #ruby on rails web development company #ruby on rails development company #hire ruby on rails developer #hire ruby on rails developers

Aria Barnes

Aria Barnes

1625232484

Why is Vue JS the most Preferred Choice for Responsive Web Application Development?

For more than two decades, JavaScript has facilitated businesses to develop responsive web applications for their customers. Used both client and server-side, JavaScript enables you to bring dynamics to pages through expanded functionality and real-time modifications.

Did you know!

According to a web development survey 2020, JavaScript is the most used language for the 8th year, with 67.7% of people choosing it. With this came up several javascript frameworks for frontend, backend development, or even testing.

And one such framework is Vue.Js. It is used to build simple projects and can also be advanced to create sophisticated apps using state-of-the-art tools. Beyond that, some other solid reasons give Vuejs a thumbs up for responsive web application development.

Want to know them? Then follow this blog until the end. Through this article, I will describe all the reasons and benefits of Vue js development. So, stay tuned.

Vue.Js - A Brief Introduction

Released in the year 2014 for public use, Vue.Js is an open-source JavaScript framework used to create UIs and single-page applications. It has over 77.4 million likes on Github for creating intuitive web interfaces.

The recent version is Vue.js 2.6, and is the second most preferred framework according to Stack Overflow Developer Survey 2019.

Every Vue.js development company is widely using the framework across the world for responsive web application development. It is centered around the view layer, provides a lot of functionality for the view layer, and builds single-page web applications.

Some most astonishing stats about Vue.Js:

• Vue was ranked #2 in the Front End JavaScript Framework rankings in the State of JS 2019 survey by developers.

• Approximately 427k to 693k sites are built with Vue js, according to Wappalyzer and BuiltWith statistics of June 2020.

• According to the State of JS 2019 survey, 40.5% of JavaScript developers are currently using Vue, while 34.5% have shown keen interest in using it in the future.

• In Stack Overflow's Developer Survey 2020, Vue was ranked the 3rd most popular front-end JavaScript framework.

Why is Vue.Js so popular?

• High-speed run-time performance
• Vue.Js uses a virtual DOM.
• The main focus is on the core library, while the collaborating libraries handle other features such as global state management and routing.
• Vue.JS provides responsive visual components.

Top 7 Reasons to Choose Vue JS for Web Application Development

Vue js development has certain benefits, which will encourage you to use it in your projects. For example, Vue.js is similar to Angular and React in many aspects, and it continues to enjoy increasing popularity compared to other frameworks.

The framework is only 20 kilobytes in size, making it easy for you to download files instantly. Vue.js easily beats other frameworks when it comes to loading times and usage.

Take a look at the compelling advantages of using Vue.Js for web app development.

#1 Simple Integration

Vue.Js is popular because it allows you to integrate Vue.js into other frameworks such as React, enabling you to customize the project as per your needs and requirements.

It helps you build apps with Vue.js from scratch and introduce Vue.js elements into their existing apps. Due to its ease of integration, Vue.js is becoming a popular choice for web development as it can be used with various existing web applications.

You can feel free to include Vue.js CDN and start using it. Most third-party Vue components and libraries are additionally accessible and supported with the Vue.js CDN.

You don't need to set up node and npm to start using Vue.js. This implies that it helps develop new web applications, just like modifying previous applications.

The diversity of components allows you to create different types of web applications and replace existing frameworks. In addition, you can also choose to hire Vue js developers to use the technology to experiment with many other JavaScript applications.

#2 Easy to Understand

One of the main reasons for the growing popularity of Vue.Js is that the framework is straightforward to understand for individuals. This means that you can easily add Vue.Js to your web projects.

Also, Vue.Js has a well-defined architecture for storing your data with life-cycle and custom methods. Vue.Js also provides additional features such as watchers, directives, and computed properties, making it extremely easy to build modern apps and web applications with ease.

Another significant advantage of using the Vue.Js framework is that it makes it easy to build small and large-scale web applications in the shortest amount of time.

#3 Well-defined Ecosystem

The VueJS ecosystem is vibrant and well-defined, allowing Vue.Js development company to switch users to VueJS over other frameworks for web app development.

Without spending hours, you can easily find solutions to your problems. Furthermore, VueJs lets you choose only the building blocks you need.

Although the main focus of Vue is the view layer, with the help of Vue Router, Vue Test Utils, Vuex, and Vue CLI, you can find solutions and recommendations for frequently occurring problems.

The problems fall into these categories, and hence it becomes easy for programmers to get started with coding right away and not waste time figuring out how to use these tools.

The Vue ecosystem is easy to customize and scales between a library and a framework. Compared to other frameworks, its development speed is excellent, and it can also integrate different projects. This is the reason why most website development companies also prefer the Vue.Js ecosystem over others.

#4 Flexibility

Another benefit of going with Vue.Js for web app development needs is flexibility. Vue.Js provides an excellent level of flexibility. And makes it easier for web app development companies to write their templates in HTML, JavaScript, or pure JavaScript using virtual nodes.

Another significant benefit of using Vue.Js is that it makes it easier for developers to work with tools like templating engines, CSS preprocessors, and type checking tools like TypeScript.

#5 Two-Way Communication

Vue.Js is an excellent option for you because it encourages two-way communication. This has become possible with the MVVM architecture to handle HTML blocks. In this way, Vue.Js is very similar to Angular.Js, making it easier to handle HTML blocks as well.

With Vue.Js, two-way data binding is straightforward. This means that any changes made by the developer to the UI are passed to the data, and the changes made to the data are reflected in the UI.

This is also one reason why Vue.Js is also known as reactive because it can react to changes made to the data. This sets it apart from other libraries such as React.Js, which are designed to support only one-way communication.

#6 Detailed Documentation

One essential thing is well-defined documentation that helps you understand the required mechanism and build your application with ease. It shows all the options offered by the framework and related best practice examples.

Vue has excellent docs, and its API references are one of the best in the industry. They are well written, clear, and accessible in dealing with everything you need to know to build a Vue application.

Besides, the documentation at Vue.js is constantly improved and updated. It also includes a simple introductory guide and an excellent overview of the API. Perhaps, this is one of the most detailed documentation available for this type of language.

#7 Large Community Support

Support for the platform is impressive. In 2018, support continued to impress as every question was answered diligently. Over 6,200 problems were solved with an average resolution time of just six hours.

To support the community, there are frequent release cycles of updated information. Furthermore, the community continues to grow and develop with backend support from developers.



Wrapping Up

VueJS is an incredible choice for responsive web app development. Since it is lightweight and user-friendly, it builds a fast and integrated web application. The capabilities and potential of VueJS for web app development are extensive.

While Vuejs is simple to get started with, using it to build scalable web apps requires professionalism. Hence, you can approach a top Vue js development company in India to develop high-performing web apps.

Equipped with all the above features, it doesn't matter whether you want to build a small concept app or a full-fledged web app; Vue.Js is the most performant you can rely on.

Original source

 

#vue js development company #vue js development company in india #vue js development company india #vue js development services #vue js development #vue js development companies

Luna  Mosciski

Luna Mosciski

1600583123

8 Popular Websites That Use The Vue.JS Framework

In this article, we are going to list out the most popular websites using Vue JS as their frontend framework.

Vue JS is one of those elite progressive JavaScript frameworks that has huge demand in the web development industry. Many popular websites are developed using Vue in their frontend development because of its imperative features.

This framework was created by Evan You and still it is maintained by his private team members. Vue is of course an open-source framework which is based on MVVM concept (Model-view view-Model) and used extensively in building sublime user-interfaces and also considered a prime choice for developing single-page heavy applications.

Released in February 2014, Vue JS has gained 64,828 stars on Github, making it very popular in recent times.

Evan used Angular JS on many operations while working for Google and integrated many features in Vue to cover the flaws of Angular.

“I figured, what if I could just extract the part that I really liked about Angular and build something really lightweight." - Evan You

#vuejs #vue #vue-with-laravel #vue-top-story #vue-3 #build-vue-frontend #vue-in-laravel #vue.js