require_relative '../lib' class VueCreate def initialize @input = InputLoop.new @pwd = FileUtils.pwd @root = ::Rails.root @pack = @root.join('package.json') @src_dir = Pathname.new(__FILE__).dirname.join('..', '..', 'source') end def self.run! new.start end def start check_node! FileUtils.chdir(@root) @pending_install = false begin package_manager? install_vue_cli run_vue_create? install_dev_deps @pm.install if @pending_install delete_vue_sample? copy_demo? copy_config generate_vue_yml fix_jest_config! puts 'vue:create finished!' ensure FileUtils.chdir(@pwd) end end private def check_node! @pm = VueCli::Rails::NodeEnv.new abort('Cannot find node.js') unless @pm.node? end def package_manager? yarn = @pm.yarn_version npm = @pm.npm_version abort('Cannot find npm or yarn') unless yarn || npm input = if yarn && npm @input.gets( 'Which package manager to use?', @root.join('package-lock.json').exist? ? 'yN' : 'Yn', y: 'yarn', n: 'npm', ) else npm ? 'n' : 'y' end @pm.use!(input == 'n' ? :npm : :yarn) puts "Using package manager: #{@pm.package_manager}" end def install_vue_cli return if @pm.vue? puts "@vue/cli haven't been installed" pm.global_add('@vue/cli') end def run_vue_create? pack_input = 'y' if @pack.exist? puts 'Detected `package.json`!' pack_input = @input.gets( ' Do you want `vue create?` to overwrite your package.json', 'yAks', a: 'Auto', k: 'Keep', s: 'Skip vue create', ) end return if pack_input == 's' gi_input = 'y' gi = @root.join('.gitignore') if gi.exist? puts 'Detected `.gitignore`!' gi_input = @input.gets( ' Do you want `vue create?` to overwrite your .gitignore', 'yMk', m: 'Merge', k: 'Keep', ) end # backups vue_config = @root.join('vue.config.js') backup_vue_config = vue_config.exist? src_json = JSON.parse(@pack.read) if pack_input != 'y' gi_lines = gi.read.split("\n") if gi_input != 'y' if backup_vue_config FileUtils.mv(vue_config, "#{vue_config}.backup") # will be recreated FileUtils.rm_f(@root.join('vue.rails.js')) end pub_dir = @root.join('public') FileUtils.mv(pub_dir, "#{pub_dir}.backup") begin @pm.exec('vue create', '', "-n -m #{@pm.package_manager} .") ensure # restore backups FileUtils.rm_rf(pub_dir) if pub_dir.exist? FileUtils.mv("#{pub_dir}.backup", pub_dir) FileUtils.mv("#{vue_config}.backup", vue_config) if backup_vue_config end # merge gitignore if gi_input == 'm' old_gi_line_count = gi_lines.size old_gi = Set.new(gi_lines.map(&:strip)) gi.read.split("\n").map(&:strip).find_all(&:present?).each do |ln| gi_lines << ln unless old_gi.include?(ln) end gi.write(gi_lines.map { |ln| "#{ln}\n" }.join('')) if gi_lines.size > old_gi_line_count elsif gi_input == 'k' gi.write(gi_lines.join('')) end # check packages.json return if pack_input == 'y' dst_json = JSON.parse(@pack.read) return if dst_json == src_json # merge packages.json src_json, dst_json = [dst_json, src_json] if pack_input == 'a' dst_json.deep_merge!(src_json) @pack.write(JSON.pretty_generate(dst_json)) @pending_install = true end def install_dev_deps package = JSON.parse(@pack.read) dev_deps = package['devDependencies'] dd = %w[webpack-assets-manifest js-yaml].find_all do |dep| !dev_deps.key?(dep) end if dd.any? @pm.add("-D #{dd.join(' ')}") @pending_install = false end end def delete_vue_sample? %w[src dist].each do |fn| file = @root.join(fn) next unless file.exist? puts "Detected `#{fn}` (should be generated by vue-cli)" FileUtils.rm_rf(file.to_s) if @input.gets(" Do you want to delete #{file}?") == 'y' end end def copy_demo? return unless @input.gets('Do you want to copy demo code?', 'yN') == 'y' FileUtils.cp_r(@src_dir.join('app'), @root) routes = @root.join('config', 'routes.rb') return unless routes.exist? route_lines = routes.read.split("\n") foo = false bar = false route_lines.each do |line| foo ||= line.include?('vue#foo') bar ||= line.include?('vue#bar') end return if foo && bar end_line = route_lines.rindex { |ln| ln =~ /^\s*end\b/ } return if end_line.blank? route_lines.insert(end_line, " get 'vue/bar' => 'vue#bar'") unless bar route_lines.insert(end_line, " get 'vue/foo' => 'vue#foo'") unless foo route_lines.insert(end_line, ' # Example of vue_cli-rails') routes.write(route_lines.join("\n")) end def copy_config puts 'Copying configuration files...' FileUtils.cp(@src_dir.join('vue.rails.js'), "#{@root}/") if @root.join('vue.config.js').exist? puts 'Detected `vue.config.js`!' return if @input.gets(' Do you want to overwrite vue.config.js?', 'yN') == 'n' end FileUtils.cp(@src_dir.join('vue.config.js'), "#{@root}/") end def generate_vue_yml yml_dest = @root.join('config', 'vue.yml') if yml_dest.exist? puts 'Detected `config/vue.yml`!' return if @input.gets(' Do you want to overwrite config/vue.yml?') == 'n' end yml = @src_dir.join('vue.yml').read yml = yml.sub('${PACKAGE_MANAGER}', @pm.package_manager.to_s) yml_dest.write(yml) end def fix_jest_config! jest_file = @root.join('jest.config.js') return unless jest_file.exist? jest_config = %x`node -e "console.log(JSON.stringify(require('./jest.config.js')))"` jest_config = JSON.parse(jest_config) jest_config.delete('moduleNameMapper') jest = <<~JS const { jestModuleNameMapper: moduleNameMapper } = require('./vue.rails'); module.exports = #{JSON.pretty_generate(jest_config)}_MODULE_NAME_MAPPER_; JS jest_file.write(jest.sub(/\n?}_MODULE_NAME_MAPPER_/, ",\n moduleNameMapper\n}")) dev_deps = JSON.parse(@pack.read)['devDependencies'] return unless dev_deps['eslint'].present? @pm.exec('eslint', jest_file.to_s, '--fix') rescue => e STDERR.puts e.message end end