github.com/JarrahG/buffalocli@v0.0.0-20230801092127-b85bfd5d395a/internal/genny/assets/webpack/webpack.go (about)

     1  package webpack
     2  
     3  import (
     4  	"embed"
     5  	"fmt"
     6  	"io/fs"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  
    12  	"github.com/gobuffalo/genny/v2"
    13  	"github.com/gobuffalo/genny/v2/gogen"
    14  )
    15  
    16  const YARN = "yarn"
    17  
    18  //go:embed templates/* templates/assets/css/_buffalo.scss.tmpl
    19  var templates embed.FS
    20  
    21  // Templates used for generating webpack
    22  // (exported mostly for the "fix" command)
    23  func Templates() (fs.FS, error) {
    24  	return fs.Sub(templates, "templates")
    25  }
    26  
    27  // BinPath is the path to the local install of webpack
    28  var BinPath = func() string {
    29  	s := filepath.Join("node_modules", ".bin", "webpack")
    30  	if runtime.GOOS == "windows" {
    31  		s += ".cmd"
    32  	}
    33  	return s
    34  }()
    35  
    36  // New generator for creating webpack asset files
    37  func New(opts *Options) (*genny.Generator, error) {
    38  	g := genny.New()
    39  
    40  	if err := opts.Validate(); err != nil {
    41  		return g, err
    42  	}
    43  
    44  	g.RunFn(func(r *genny.Runner) error {
    45  		if opts.App.WithYarn {
    46  			if _, err := r.LookPath(YARN); err == nil {
    47  				return nil
    48  			}
    49  			// If yarn is not installed, it still can be installed with npm.
    50  		}
    51  		if _, err := r.LookPath("npm"); err != nil {
    52  			return fmt.Errorf("could not find npm executable")
    53  		}
    54  		return nil
    55  	})
    56  
    57  	temp, err := Templates()
    58  	if err != nil {
    59  		return g, err
    60  	}
    61  
    62  	if err := g.FS(temp); err != nil {
    63  		return g, err
    64  	}
    65  
    66  	data := map[string]interface{}{
    67  		"opts": opts,
    68  	}
    69  	t := gogen.TemplateTransformer(data, gogen.TemplateHelpers)
    70  	g.Transformer(t)
    71  	g.Transformer(genny.Dot())
    72  
    73  	// TODO: workaround for 1.16, remove when we upgrade to 1.17 and rename "dot-*" files back to "-dot-*"
    74  	g.Transformer(genny.NewTransformer("*", func(f genny.File) (genny.File, error) {
    75  		name := f.Name()
    76  		if strings.HasPrefix(name, "dot-") {
    77  			name = strings.TrimPrefix(name, "dot-")
    78  			name = "." + name
    79  		}
    80  		return genny.NewFile(name, f), nil
    81  	}))
    82  	g.Transformer(genny.Replace("/dot-", "/."))
    83  
    84  	g.RunFn(func(r *genny.Runner) error {
    85  		return installPkgs(r, opts)
    86  	})
    87  
    88  	return g, nil
    89  }
    90  
    91  func installPkgs(r *genny.Runner, opts *Options) error {
    92  	command := YARN
    93  	args := []string{"install"}
    94  
    95  	if !opts.App.WithYarn {
    96  		command = "npm"
    97  		args = []string{"install", "--no-progress", "--save"}
    98  	} else {
    99  		if err := installYarn(r); err != nil {
   100  			return err
   101  		}
   102  		if err := setupYarnBerry(r); err != nil {
   103  			return err
   104  		}
   105  	}
   106  
   107  	r.Exec(exec.Command(command, "--version"))
   108  	c := exec.Command(command, args...)
   109  	c.Stdout = yarnWriter{
   110  		fn: r.Logger.Debug,
   111  	}
   112  	c.Stderr = yarnWriter{
   113  		fn: r.Logger.Debug,
   114  	}
   115  	return r.Exec(c)
   116  }
   117  
   118  type yarnWriter struct {
   119  	fn func(...interface{})
   120  }
   121  
   122  func (y yarnWriter) Write(p []byte) (int, error) {
   123  	y.fn(string(p))
   124  	return len(p), nil
   125  }
   126  
   127  func installYarn(r *genny.Runner) error {
   128  	// if there's no yarn, install it!
   129  	if _, err := r.LookPath(YARN); err == nil {
   130  		return nil
   131  	}
   132  	yargs := []string{"install", "-g", "yarn"}
   133  	return r.Exec(exec.Command("npm", yargs...))
   134  }
   135  
   136  func setupYarnBerry(r *genny.Runner) error {
   137  	if err := r.Exec(exec.Command(YARN, "--version")); err != nil {
   138  		return err
   139  	}
   140  	if err := r.Exec(exec.Command(YARN, "set", "version", "berry")); err != nil {
   141  		return err
   142  	}
   143  	// the yarnrc config format is different between classic and berry so
   144  	// it should be configured after berry installation (set version)
   145  	if err := r.Exec(exec.Command(YARN, "config", "set", "enableGlobalCache", "true")); err != nil {
   146  		return err
   147  	}
   148  	if err := r.Exec(exec.Command(YARN, "config", "set", "logFilters", "--json", `[{"code":"YN0013","level":"discard"}]`)); err != nil {
   149  		return err
   150  	}
   151  	return nil
   152  }