webpacker 1.2 → 2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +93 -9
  4. data/Gemfile.lock +2 -2
  5. data/README.md +979 -93
  6. data/lib/install/angular.rb +2 -2
  7. data/lib/install/bin/webpack-dev-server.tt +20 -10
  8. data/lib/install/bin/webpack.tt +10 -15
  9. data/lib/install/config/.babelrc +13 -1
  10. data/lib/install/config/loaders/core/sass.js +3 -2
  11. data/lib/install/config/loaders/installers/elm.js +20 -0
  12. data/lib/install/config/loaders/installers/vue.js +1 -0
  13. data/lib/install/config/webpack/configuration.js +22 -13
  14. data/lib/install/config/webpack/development.js +17 -1
  15. data/lib/install/config/webpack/production.js +16 -2
  16. data/lib/install/config/webpack/shared.js +15 -11
  17. data/lib/install/config/{webpack/paths.yml → webpacker.yml} +12 -7
  18. data/lib/install/elm.rb +29 -0
  19. data/lib/install/examples/angular/tsconfig.json +1 -0
  20. data/lib/install/examples/elm/Main.elm +54 -0
  21. data/lib/install/examples/elm/hello_elm.js +11 -0
  22. data/lib/install/examples/vue/hello_vue.js +4 -8
  23. data/lib/install/react.rb +2 -2
  24. data/lib/install/template.rb +10 -11
  25. data/lib/install/vue.rb +2 -2
  26. data/lib/tasks/installers.rake +1 -0
  27. data/lib/tasks/webpacker.rake +11 -9
  28. data/lib/tasks/webpacker/check_webpack_binstubs.rake +11 -0
  29. data/lib/tasks/webpacker/check_yarn.rake +6 -3
  30. data/lib/tasks/webpacker/clobber.rake +3 -3
  31. data/lib/tasks/webpacker/compile.rake +14 -20
  32. data/lib/tasks/webpacker/verify_install.rake +2 -2
  33. data/lib/tasks/webpacker/yarn_install.rake +2 -2
  34. data/lib/webpacker.rb +16 -1
  35. data/lib/webpacker/compiler.rb +20 -0
  36. data/lib/webpacker/configuration.rb +30 -22
  37. data/lib/webpacker/env.rb +2 -6
  38. data/lib/webpacker/helper.rb +0 -2
  39. data/lib/webpacker/manifest.rb +23 -6
  40. data/lib/webpacker/version.rb +1 -1
  41. data/package.json +1 -1
  42. data/test/configuration_test.rb +32 -0
  43. data/test/env_test.rb +3 -5
  44. data/test/helper_test.rb +23 -0
  45. data/test/manifest_test.rb +30 -0
  46. data/test/test_app/config/secrets.yml +5 -0
  47. data/test/test_app/public/packs/manifest.json +4 -0
  48. data/test/webpacker_test.rb +2 -1
  49. metadata +20 -7
  50. data/lib/install/bin/yarn.tt +0 -11
  51. data/lib/install/config/webpack/development.server.js +0 -17
  52. data/lib/install/config/webpack/development.server.yml +0 -17
@@ -1,6 +1,6 @@
1
1
  require "webpacker/configuration"
2
2
 
3
- puts "Copying angular loader to #{Webpacker::Configuration.config_path}/loaders"
3
+ puts "Copying angular loader to config/webpack/loaders"
4
4
  copy_file "#{__dir__}/config/loaders/installers/angular.js", "config/webpack/loaders/angular.js"
5
5
 
6
6
  puts "Copying angular example entry file to #{Webpacker::Configuration.entry_path}"
@@ -13,6 +13,6 @@ puts "Copying tsconfig.json to the Rails root directory for typescript"
13
13
  copy_file "#{__dir__}/examples/angular/tsconfig.json", "tsconfig.json"
14
14
 
15
15
  puts "Installing all angular dependencies"
16
- run "./bin/yarn add typescript ts-loader core-js zone.js rxjs @angular/core @angular/common @angular/compiler @angular/platform-browser @angular/platform-browser-dynamic"
16
+ run "yarn add typescript ts-loader core-js zone.js rxjs @angular/core @angular/common @angular/compiler @angular/platform-browser @angular/platform-browser-dynamic"
17
17
 
18
18
  puts "Webpacker now supports angular and typescript 🎉"
@@ -10,24 +10,34 @@ RAILS_ENV = ENV["RAILS_ENV"]
10
10
  ENV["NODE_ENV"] ||= RAILS_ENV
11
11
  NODE_ENV = ENV["NODE_ENV"]
12
12
 
13
- APP_PATH = File.expand_path("../", __dir__)
14
- CONFIG_PATH = File.join(APP_PATH, "config/webpack/paths.yml")
13
+ APP_PATH = File.expand_path("../", __dir__)
14
+ CONFIG_FILE = File.join(APP_PATH, "config/webpacker.yml")
15
+ NODE_MODULES_PATH = File.join(APP_PATH, "node_modules")
16
+ WEBPACK_CONFIG = File.join(APP_PATH, "config/webpack/development.js")
17
+
18
+ def args(key)
19
+ index = ARGV.index(key)
20
+ index ? ARGV[index + 1] : nil
21
+ end
15
22
 
16
23
  begin
17
- paths = YAML.load(File.read(CONFIG_PATH))[NODE_ENV]
24
+ dev_server = YAML.load_file(CONFIG_FILE)["development"]["dev_server"]
18
25
 
19
- NODE_MODULES_PATH = File.join(APP_PATH.shellescape, paths["node_modules"])
20
- WEBPACK_CONFIG_PATH = File.join(APP_PATH.shellescape, paths["config"])
26
+ DEV_SERVER_HOST = "http#{"s" if args('--https') || dev_server["https"]}://#{args('--host') || dev_server["host"]}:#{args('--port') || dev_server["port"]}"
21
27
 
22
- WEBPACK_BIN = "#{NODE_MODULES_PATH}/.bin/webpack-dev-server"
23
- DEV_SERVER_CONFIG = "#{WEBPACK_CONFIG_PATH}/development.server.js"
24
28
  rescue Errno::ENOENT, NoMethodError
25
- puts "Configuration not found in config/webpacker/paths.yml."
29
+ puts "Webpack dev_server configuration not found in #{CONFIG_FILE}."
26
30
  puts "Please run bundle exec rails webpacker:install to install webpacker"
27
31
  exit!
28
32
  end
29
33
 
34
+ newenv = {
35
+ "NODE_PATH" => NODE_MODULES_PATH.shellescape,
36
+ "ASSET_HOST" => DEV_SERVER_HOST.shellescape
37
+ }.freeze
38
+
39
+ cmdline = ["yarn", "run", "webpack-dev-server", "--", "--progress", "--color", "--config", WEBPACK_CONFIG] + ARGV
40
+
30
41
  Dir.chdir(APP_PATH) do
31
- exec "NODE_PATH=#{NODE_MODULES_PATH} #{WEBPACK_BIN} --progress --color " \
32
- "--config #{DEV_SERVER_CONFIG} #{ARGV.join(" ")}"
42
+ exec newenv, *cmdline
33
43
  end
@@ -5,29 +5,24 @@ require "shellwords"
5
5
  require "yaml"
6
6
 
7
7
  ENV["RAILS_ENV"] ||= "development"
8
- RAILS_ENV = ENV["RAILS_ENV"]
8
+ RAILS_ENV = ENV["RAILS_ENV"]
9
9
 
10
10
  ENV["NODE_ENV"] ||= RAILS_ENV
11
- NODE_ENV = ENV["NODE_ENV"]
11
+ NODE_ENV = ENV["NODE_ENV"]
12
12
 
13
- APP_PATH = File.expand_path("../", __dir__)
14
- CONFIG_PATH = File.join(APP_PATH, "config/webpack/paths.yml")
13
+ APP_PATH = File.expand_path("../", __dir__)
14
+ NODE_MODULES_PATH = File.join(APP_PATH, "node_modules")
15
+ WEBPACK_CONFIG = File.join(APP_PATH, "config/webpack/#{NODE_ENV}.js")
15
16
 
16
- begin
17
- paths = YAML.load(File.read(CONFIG_PATH))[NODE_ENV]
18
-
19
- NODE_MODULES_PATH = File.join(APP_PATH.shellescape, paths["node_modules"])
20
- WEBPACK_CONFIG_PATH = File.join(APP_PATH.shellescape, paths["config"])
21
- rescue Errno::ENOENT, NoMethodError
22
- puts "Configuration not found in config/webpack/paths.yml"
17
+ unless File.exist?(WEBPACK_CONFIG)
18
+ puts "Webpack configuration not found."
23
19
  puts "Please run bundle exec rails webpacker:install to install webpacker"
24
20
  exit!
25
21
  end
26
22
 
27
- WEBPACK_BIN = "#{NODE_MODULES_PATH}/.bin/webpack"
28
- WEBPACK_CONFIG = "#{WEBPACK_CONFIG_PATH}/#{NODE_ENV}.js"
23
+ newenv = { "NODE_PATH" => NODE_MODULES_PATH.shellescape }
24
+ cmdline = ["yarn", "run", "webpack", "--", "--config", WEBPACK_CONFIG] + ARGV
29
25
 
30
26
  Dir.chdir(APP_PATH) do
31
- exec "NODE_PATH=#{NODE_MODULES_PATH} #{WEBPACK_BIN} --config #{WEBPACK_CONFIG}" \
32
- " #{ARGV.join(" ")}"
27
+ exec newenv, *cmdline
33
28
  end
@@ -1,5 +1,17 @@
1
1
  {
2
2
  "presets": [
3
- ["env", { "modules": false } ]
3
+ ["env", {
4
+ "modules": false,
5
+ "targets": {
6
+ "browsers": "> 1%",
7
+ "uglify": true
8
+ },
9
+ "useBuiltIns": true
10
+ }]
11
+ ],
12
+
13
+ "plugins": [
14
+ "syntax-dynamic-import",
15
+ ["transform-class-properties", { "spec": true }]
4
16
  ]
5
17
  }
@@ -7,8 +7,9 @@ module.exports = {
7
7
  fallback: 'style-loader',
8
8
  use: [
9
9
  { loader: 'css-loader', options: { minimize: env.NODE_ENV === 'production' } },
10
- 'postcss-loader',
11
- 'sass-loader'
10
+ { loader: 'postcss-loader', options: { sourceMap: true } },
11
+ 'resolve-url-loader',
12
+ { loader: 'sass-loader', options: { sourceMap: true } }
12
13
  ]
13
14
  })
14
15
  }
@@ -0,0 +1,20 @@
1
+ const path = require('path')
2
+ const { env } = require('../configuration.js')
3
+
4
+ const elmSource = path.resolve(process.cwd())
5
+ const elmMake = `${elmSource}/node_modules/.bin/elm-make`
6
+ const elmDefaultOptions = `cwd=${elmSource}&pathToMake=${elmMake}`
7
+
8
+ const loaderOptions = () => {
9
+ if (env.NODE_ENV === 'production') {
10
+ return `elm-webpack-loader?${elmDefaultOptions}`
11
+ }
12
+
13
+ return `elm-hot-loader!elm-webpack-loader?${elmDefaultOptions}&verbose=true&warn=true&debug=true`
14
+ }
15
+
16
+ module.exports = {
17
+ test: /\.elm$/,
18
+ exclude: [/elm-stuff/, /node_modules/],
19
+ loader: loaderOptions()
20
+ }
@@ -2,6 +2,7 @@ module.exports = {
2
2
  test: /.vue$/,
3
3
  loader: 'vue-loader',
4
4
  options: {
5
+ extractCSS: true,
5
6
  loaders: {
6
7
  js: 'babel-loader',
7
8
  file: 'file-loader',
@@ -1,26 +1,35 @@
1
- // Common configuration for webpacker loaded from config/webpack/paths.yml
1
+ // Common configuration for webpacker loaded from config/webpacker.yml
2
2
 
3
3
  const { join, resolve } = require('path')
4
4
  const { env } = require('process')
5
5
  const { safeLoad } = require('js-yaml')
6
6
  const { readFileSync } = require('fs')
7
7
 
8
- const configPath = resolve('config', 'webpack')
8
+ const configPath = resolve('config', 'webpacker.yml')
9
9
  const loadersDir = join(__dirname, 'loaders')
10
- const paths = safeLoad(readFileSync(join(configPath, 'paths.yml'), 'utf8'))[env.NODE_ENV]
11
- const devServer = safeLoad(readFileSync(join(configPath, 'development.server.yml'), 'utf8'))[env.NODE_ENV]
10
+ const settings = safeLoad(readFileSync(configPath), 'utf8')[env.NODE_ENV]
12
11
 
13
- // Compute public path based on environment and ASSET_HOST in production
14
- const ifHasCDN = env.ASSET_HOST !== undefined && env.NODE_ENV === 'production'
15
- const devServerUrl = `http://${devServer.host}:${devServer.port}/${paths.entry}/`
16
- const publicUrl = ifHasCDN ? `${env.ASSET_HOST}/${paths.entry}/` : `/${paths.entry}/`
17
- const publicPath = env.NODE_ENV !== 'production' ? devServerUrl : publicUrl
12
+ function removeOuterSlashes(string) {
13
+ return string.replace(/^\/*/, '').replace(/\/*$/, '')
14
+ }
15
+
16
+ function formatPublicPath(host = '', path = '') {
17
+ let formattedHost = removeOuterSlashes(host)
18
+ if (formattedHost && !/^http/i.test(formattedHost)) {
19
+ formattedHost = `//${formattedHost}`
20
+ }
21
+ const formattedPath = removeOuterSlashes(path)
22
+ return `${formattedHost}/${formattedPath}/`
23
+ }
24
+
25
+ const output = {
26
+ path: resolve('public', settings.public_output_path),
27
+ publicPath: formatPublicPath(env.ASSET_HOST, settings.public_output_path)
28
+ }
18
29
 
19
30
  module.exports = {
20
- devServer,
31
+ settings,
21
32
  env,
22
- paths,
23
33
  loadersDir,
24
- publicUrl,
25
- publicPath
34
+ output
26
35
  }
@@ -2,9 +2,10 @@
2
2
 
3
3
  const merge = require('webpack-merge')
4
4
  const sharedConfig = require('./shared.js')
5
+ const { settings, output } = require('./configuration.js')
5
6
 
6
7
  module.exports = merge(sharedConfig, {
7
- devtool: 'sourcemap',
8
+ devtool: 'cheap-eval-source-map',
8
9
 
9
10
  stats: {
10
11
  errorDetails: true
@@ -12,5 +13,20 @@ module.exports = merge(sharedConfig, {
12
13
 
13
14
  output: {
14
15
  pathinfo: true
16
+ },
17
+
18
+ devServer: {
19
+ clientLogLevel: 'none',
20
+ https: settings.dev_server.https,
21
+ host: settings.dev_server.host,
22
+ port: settings.dev_server.port,
23
+ contentBase: output.path,
24
+ publicPath: output.publicPath,
25
+ compress: true,
26
+ headers: { 'Access-Control-Allow-Origin': '*' },
27
+ historyApiFallback: true,
28
+ watchOptions: {
29
+ ignored: /node_modules/
30
+ }
15
31
  }
16
32
  })
@@ -9,13 +9,27 @@ const sharedConfig = require('./shared.js')
9
9
 
10
10
  module.exports = merge(sharedConfig, {
11
11
  output: { filename: '[name]-[chunkhash].js' },
12
+ devtool: 'source-map',
13
+ stats: 'normal',
12
14
 
13
15
  plugins: [
14
- new webpack.optimize.UglifyJsPlugin(),
16
+ new webpack.optimize.UglifyJsPlugin({
17
+ minimize: true,
18
+ sourceMap: true,
19
+
20
+ compress: {
21
+ warnings: false
22
+ },
23
+
24
+ output: {
25
+ comments: false
26
+ }
27
+ }),
28
+
15
29
  new CompressionPlugin({
16
30
  asset: '[path].gz[query]',
17
31
  algorithm: 'gzip',
18
- test: /\.(js|css|svg|eot|ttf|woff|woff2)$/
32
+ test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/
19
33
  })
20
34
  ]
21
35
  })
@@ -9,16 +9,17 @@ const { sync } = require('glob')
9
9
  const ExtractTextPlugin = require('extract-text-webpack-plugin')
10
10
  const ManifestPlugin = require('webpack-manifest-plugin')
11
11
  const extname = require('path-complete-extname')
12
- const { env, paths, publicPath, loadersDir } = require('./configuration.js')
12
+ const { env, settings, output, loadersDir } = require('./configuration.js')
13
13
 
14
- const extensionGlob = `**/*{${paths.extensions.join(',')}}*`
15
- const packPaths = sync(join(paths.source, paths.entry, extensionGlob))
14
+ const extensionGlob = `**/*{${settings.extensions.join(',')}}*`
15
+ const entryPath = join(settings.source_path, settings.source_entry_path)
16
+ const packPaths = sync(join(entryPath, extensionGlob))
16
17
 
17
18
  module.exports = {
18
19
  entry: packPaths.reduce(
19
20
  (map, entry) => {
20
21
  const localMap = map
21
- const namespace = relative(join(paths.source, paths.entry), dirname(entry))
22
+ const namespace = relative(join(entryPath), dirname(entry))
22
23
  localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry)
23
24
  return localMap
24
25
  }, {}
@@ -26,8 +27,8 @@ module.exports = {
26
27
 
27
28
  output: {
28
29
  filename: '[name].js',
29
- path: resolve(paths.output, paths.entry),
30
- publicPath
30
+ path: output.path,
31
+ publicPath: output.publicPath
31
32
  },
32
33
 
33
34
  module: {
@@ -37,18 +38,21 @@ module.exports = {
37
38
  plugins: [
38
39
  new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
39
40
  new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css'),
40
- new ManifestPlugin({ fileName: paths.manifest, publicPath, writeToFileEmit: true })
41
+ new ManifestPlugin({
42
+ publicPath: output.publicPath,
43
+ writeToFileEmit: true
44
+ })
41
45
  ],
42
46
 
43
47
  resolve: {
44
- extensions: paths.extensions,
48
+ extensions: settings.extensions,
45
49
  modules: [
46
- resolve(paths.source),
47
- resolve(paths.node_modules)
50
+ resolve(settings.source_path),
51
+ 'node_modules'
48
52
  ]
49
53
  },
50
54
 
51
55
  resolveLoader: {
52
- modules: [paths.node_modules]
56
+ modules: ['node_modules']
53
57
  }
54
58
  }
@@ -1,14 +1,13 @@
1
1
  # Note: You must restart bin/webpack-dev-server for changes to take effect
2
2
 
3
3
  default: &default
4
- config: config/webpack
5
- entry: packs
6
- output: public
7
- manifest: manifest.json
8
- node_modules: node_modules
9
- source: app/javascript
4
+ source_path: app/javascript
5
+ source_entry_path: packs
6
+ public_output_path: packs
7
+
10
8
  extensions:
11
9
  - .coffee
10
+ - .erb
12
11
  - .js
13
12
  - .jsx
14
13
  - .ts
@@ -25,9 +24,15 @@ default: &default
25
24
  development:
26
25
  <<: *default
27
26
 
27
+ dev_server:
28
+ host: 0.0.0.0
29
+ port: 8080
30
+ https: false
31
+
28
32
  test:
29
33
  <<: *default
30
- manifest: manifest-test.json
34
+
35
+ public_output_path: packs-test
31
36
 
32
37
  production:
33
38
  <<: *default
@@ -0,0 +1,29 @@
1
+ require "webpacker/configuration"
2
+
3
+ puts "Copying elm loader to config/webpack/loaders"
4
+ copy_file "#{__dir__}/config/loaders/installers/elm.js",
5
+ "config/webpack/loaders/elm.js"
6
+
7
+ puts "Copying elm example entry file to #{Webpacker::Configuration.entry_path}"
8
+ copy_file "#{__dir__}/examples/elm/Main.elm", "#{Webpacker::Configuration.entry_path}/Main.elm"
9
+
10
+ puts "Copying elm app file to #{Webpacker::Configuration.entry_path}"
11
+ copy_file "#{__dir__}/examples/elm/hello_elm.js",
12
+ "#{Webpacker::Configuration.entry_path}/hello_elm.js"
13
+
14
+ puts "Installing all elm dependencies"
15
+ run "yarn add elm elm-webpack-loader"
16
+ run "yarn add --dev elm-hot-loader"
17
+ run "yarn run elm package install -- --yes"
18
+
19
+ puts "Updating Webpack paths to include Elm file extension"
20
+ insert_into_file Webpacker::Configuration.file_path, " - .elm\n", after: /extensions:\n/
21
+
22
+ puts "Updating elm source location"
23
+ source_path = File.join(Webpacker::Configuration.source, Webpacker::Configuration.fetch(:source_entry_path))
24
+ gsub_file "elm-package.json", /\"\.\"\n/, %("#{source_path}"\n)
25
+
26
+ puts "Updating .gitignore to include elm-stuff folder"
27
+ insert_into_file ".gitignore", "/elm-stuff\n", before: "/node_modules\n"
28
+
29
+ puts "Webpacker now supports elm 🎉"
@@ -12,6 +12,7 @@
12
12
  "exclude": [
13
13
  "**/*.spec.ts",
14
14
  "node_modules",
15
+ "vendor",
15
16
  "public"
16
17
  ],
17
18
  "compileOnSave": false
@@ -0,0 +1,54 @@
1
+ module Main exposing (..)
2
+
3
+ import Html exposing (Html, h1, text)
4
+ import Html.Attributes exposing (style)
5
+
6
+ -- MODEL
7
+
8
+ type alias Model =
9
+ {
10
+ }
11
+
12
+ -- INIT
13
+
14
+ init : (Model, Cmd Message)
15
+ init =
16
+ (Model, Cmd.none)
17
+
18
+ -- VIEW
19
+
20
+ view : Model -> Html Message
21
+ view model =
22
+ -- The inline style is being used for example purposes in order to keep this example simple and
23
+ -- avoid loading additional resources. Use a proper stylesheet when building your own app.
24
+ h1 [style [("display", "flex"), ("justify-content", "center")]]
25
+ [text "Hello Elm!"]
26
+
27
+ -- MESSAGE
28
+
29
+ type Message
30
+ = None
31
+
32
+ -- UPDATE
33
+
34
+ update : Message -> Model -> (Model, Cmd Message)
35
+ update message model =
36
+ (model, Cmd.none)
37
+
38
+ -- SUBSCRIPTIONS
39
+
40
+ subscriptions : Model -> Sub Message
41
+ subscriptions model =
42
+ Sub.none
43
+
44
+ -- MAIN
45
+
46
+ main : Program Never Model Message
47
+ main =
48
+ Html.program
49
+ {
50
+ init = init,
51
+ view = view,
52
+ update = update,
53
+ subscriptions = subscriptions
54
+ }