shakapacker 6.0.0.rc.6
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.
- checksums.yaml +7 -0
- data/.eslintignore +4 -0
- data/.eslintrc.js +14 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- data/.github/ISSUE_TEMPLATE/feature-request.md +18 -0
- data/.github/workflows/jest.yml +30 -0
- data/.github/workflows/js-lint.yml +31 -0
- data/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/ruby.yml +48 -0
- data/.gitignore +13 -0
- data/.node-version +1 -0
- data/.rubocop.yml +229 -0
- data/CHANGELOG.md +32 -0
- data/CONTRIBUTING.md +62 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +183 -0
- data/MIT-LICENSE +20 -0
- data/README.md +666 -0
- data/Rakefile +11 -0
- data/config/README.md +3 -0
- data/config/webpacker.yml +1 -0
- data/docs/customizing_babel_config.md +59 -0
- data/docs/deployment.md +116 -0
- data/docs/developing_webpacker.md +29 -0
- data/docs/troubleshooting.md +212 -0
- data/docs/v6_upgrade.md +158 -0
- data/gemfiles/Gemfile-rails-edge +12 -0
- data/gemfiles/Gemfile-rails.5.2.x +9 -0
- data/gemfiles/Gemfile-rails.6.0.x +9 -0
- data/gemfiles/Gemfile-rails.6.1.x +12 -0
- data/lib/install/application.js +15 -0
- data/lib/install/bin/webpacker +15 -0
- data/lib/install/bin/webpacker-dev-server +18 -0
- data/lib/install/bin/yarn +18 -0
- data/lib/install/binstubs.rb +4 -0
- data/lib/install/config/webpack/webpack.config.js +5 -0
- data/lib/install/config/webpacker.yml +64 -0
- data/lib/install/package.json +15 -0
- data/lib/install/template.rb +100 -0
- data/lib/shakapacker/utils/git_utils.rb +23 -0
- data/lib/shakapacker/utils/version_syntax_converter.rb +24 -0
- data/lib/tasks/webpacker/binstubs.rake +15 -0
- data/lib/tasks/webpacker/check_binstubs.rake +12 -0
- data/lib/tasks/webpacker/check_node.rake +31 -0
- data/lib/tasks/webpacker/check_yarn.rake +33 -0
- data/lib/tasks/webpacker/clean.rake +25 -0
- data/lib/tasks/webpacker/clobber.rake +20 -0
- data/lib/tasks/webpacker/compile.rake +45 -0
- data/lib/tasks/webpacker/info.rake +21 -0
- data/lib/tasks/webpacker/install.rake +17 -0
- data/lib/tasks/webpacker/verify_config.rake +14 -0
- data/lib/tasks/webpacker/verify_install.rake +4 -0
- data/lib/tasks/webpacker/yarn_install.rake +18 -0
- data/lib/tasks/webpacker.rake +19 -0
- data/lib/tasks/yarn.rake +38 -0
- data/lib/webpacker/commands.rb +79 -0
- data/lib/webpacker/compiler.rb +130 -0
- data/lib/webpacker/configuration.rb +111 -0
- data/lib/webpacker/dev_server.rb +72 -0
- data/lib/webpacker/dev_server_proxy.rb +33 -0
- data/lib/webpacker/dev_server_runner.rb +96 -0
- data/lib/webpacker/env.rb +43 -0
- data/lib/webpacker/helper.rb +161 -0
- data/lib/webpacker/instance.rb +41 -0
- data/lib/webpacker/manifest.rb +120 -0
- data/lib/webpacker/railtie.rb +63 -0
- data/lib/webpacker/runner.rb +23 -0
- data/lib/webpacker/version.rb +4 -0
- data/lib/webpacker/webpack_runner.rb +58 -0
- data/lib/webpacker.rb +46 -0
- data/package/__tests__/config.js +34 -0
- data/package/__tests__/dev_server.js +45 -0
- data/package/__tests__/development.js +35 -0
- data/package/__tests__/env.js +58 -0
- data/package/__tests__/index.js +9 -0
- data/package/__tests__/production.js +29 -0
- data/package/__tests__/staging.js +30 -0
- data/package/__tests__/test.js +25 -0
- data/package/babel/preset.js +41 -0
- data/package/config.js +32 -0
- data/package/configPath.js +3 -0
- data/package/dev_server.js +20 -0
- data/package/env.js +27 -0
- data/package/environments/__tests__/base.js +69 -0
- data/package/environments/base.js +116 -0
- data/package/environments/development.js +55 -0
- data/package/environments/production.js +79 -0
- data/package/environments/test.js +3 -0
- data/package/index.js +33 -0
- data/package/inliningCss.js +7 -0
- data/package/rules/babel.js +30 -0
- data/package/rules/coffee.js +6 -0
- data/package/rules/css.js +3 -0
- data/package/rules/erb.js +15 -0
- data/package/rules/file.js +23 -0
- data/package/rules/index.js +18 -0
- data/package/rules/less.js +22 -0
- data/package/rules/raw.js +5 -0
- data/package/rules/sass.js +16 -0
- data/package/rules/stylus.js +26 -0
- data/package/utils/get_style_rule.js +37 -0
- data/package/utils/helpers.js +51 -0
- data/package.json +71 -0
- data/rakelib/release.rake +57 -0
- data/test/command_test.rb +109 -0
- data/test/compiler_test.rb +68 -0
- data/test/configuration_test.rb +78 -0
- data/test/dev_server_runner_test.rb +81 -0
- data/test/dev_server_test.rb +47 -0
- data/test/engine_rake_tasks_test.rb +39 -0
- data/test/env_test.rb +23 -0
- data/test/helper_test.rb +159 -0
- data/test/manifest_test.rb +89 -0
- data/test/mounted_app/Rakefile +4 -0
- data/test/mounted_app/test/dummy/Rakefile +3 -0
- data/test/mounted_app/test/dummy/bin/rails +3 -0
- data/test/mounted_app/test/dummy/bin/rake +3 -0
- data/test/mounted_app/test/dummy/config/application.rb +10 -0
- data/test/mounted_app/test/dummy/config/environment.rb +3 -0
- data/test/mounted_app/test/dummy/config/webpacker.yml +75 -0
- data/test/mounted_app/test/dummy/config.ru +5 -0
- data/test/mounted_app/test/dummy/package.json +7 -0
- data/test/rake_tasks_test.rb +71 -0
- data/test/test_app/Rakefile +3 -0
- data/test/test_app/app/packs/entrypoints/application.js +10 -0
- data/test/test_app/app/packs/entrypoints/multi_entry.css +4 -0
- data/test/test_app/app/packs/entrypoints/multi_entry.js +4 -0
- data/test/test_app/bin/webpacker +14 -0
- data/test/test_app/bin/webpacker-dev-server +14 -0
- data/test/test_app/config/application.rb +11 -0
- data/test/test_app/config/environment.rb +4 -0
- data/test/test_app/config/initializers/inspect_autoload_paths.rb +1 -0
- data/test/test_app/config/webpack/webpack.config.js +0 -0
- data/test/test_app/config/webpacker.yml +77 -0
- data/test/test_app/config/webpacker_other_location.yml +79 -0
- data/test/test_app/config/webpacker_public_root.yml +18 -0
- data/test/test_app/config.ru +5 -0
- data/test/test_app/package.json +13 -0
- data/test/test_app/public/packs/manifest.json +50 -0
- data/test/test_app/some.config.js +0 -0
- data/test/test_app/yarn.lock +11 -0
- data/test/test_helper.rb +33 -0
- data/test/webpack_runner_test.rb +57 -0
- data/test/webpacker_test.rb +34 -0
- data/webpacker.gemspec +31 -0
- data/yarn.lock +4029 -0
- metadata +331 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* global test expect, describe */
|
|
2
|
+
|
|
3
|
+
const { chdirTestApp, chdirCwd } = require('../utils/helpers')
|
|
4
|
+
|
|
5
|
+
chdirTestApp()
|
|
6
|
+
|
|
7
|
+
describe('Env', () => {
|
|
8
|
+
beforeEach(() => jest.resetModules())
|
|
9
|
+
afterAll(chdirCwd)
|
|
10
|
+
|
|
11
|
+
test('with NODE_ENV and RAILS_ENV set to development', () => {
|
|
12
|
+
process.env.RAILS_ENV = 'development'
|
|
13
|
+
process.env.NODE_ENV = 'development'
|
|
14
|
+
expect(require('../env')).toEqual({
|
|
15
|
+
railsEnv: 'development',
|
|
16
|
+
nodeEnv: 'development',
|
|
17
|
+
isProduction: false,
|
|
18
|
+
isDevelopment: true,
|
|
19
|
+
runningWebpackDevServer: false
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('with undefined NODE_ENV and RAILS_ENV set to development', () => {
|
|
24
|
+
process.env.RAILS_ENV = 'development'
|
|
25
|
+
delete process.env.NODE_ENV
|
|
26
|
+
expect(require('../env')).toEqual({
|
|
27
|
+
railsEnv: 'development',
|
|
28
|
+
nodeEnv: 'production',
|
|
29
|
+
isProduction: true,
|
|
30
|
+
isDevelopment: false,
|
|
31
|
+
runningWebpackDevServer: false
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('with undefined NODE_ENV and RAILS_ENV', () => {
|
|
36
|
+
delete process.env.NODE_ENV
|
|
37
|
+
delete process.env.RAILS_ENV
|
|
38
|
+
expect(require('../env')).toEqual({
|
|
39
|
+
railsEnv: 'production',
|
|
40
|
+
nodeEnv: 'production',
|
|
41
|
+
isProduction: true,
|
|
42
|
+
isDevelopment: false,
|
|
43
|
+
runningWebpackDevServer: false
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('with a non-standard environment', () => {
|
|
48
|
+
process.env.RAILS_ENV = 'staging'
|
|
49
|
+
process.env.NODE_ENV = 'staging'
|
|
50
|
+
expect(require('../env')).toEqual({
|
|
51
|
+
railsEnv: 'staging',
|
|
52
|
+
nodeEnv: 'production',
|
|
53
|
+
isProduction: true,
|
|
54
|
+
isDevelopment: false,
|
|
55
|
+
runningWebpackDevServer: false
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const index = require('../index')
|
|
2
|
+
|
|
3
|
+
describe('index', () => {
|
|
4
|
+
test('exports webpack-merge v5 functions', () => {
|
|
5
|
+
expect(index.merge).toBeInstanceOf(Function)
|
|
6
|
+
expect(index.mergeWithRules).toBeInstanceOf(Function)
|
|
7
|
+
expect(index.mergeWithCustomize).toBeInstanceOf(Function)
|
|
8
|
+
})
|
|
9
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* test expect, describe, afterAll, beforeEach */
|
|
2
|
+
|
|
3
|
+
const { resolve } = require('path')
|
|
4
|
+
const { chdirTestApp, chdirCwd } = require('../utils/helpers')
|
|
5
|
+
|
|
6
|
+
chdirTestApp()
|
|
7
|
+
|
|
8
|
+
describe('Production environment', () => {
|
|
9
|
+
afterAll(chdirCwd)
|
|
10
|
+
|
|
11
|
+
describe('webpackConfig', () => {
|
|
12
|
+
beforeEach(() => jest.resetModules())
|
|
13
|
+
|
|
14
|
+
test('should use production config and environment', () => {
|
|
15
|
+
process.env.RAILS_ENV = 'production'
|
|
16
|
+
process.env.NODE_ENV = 'production'
|
|
17
|
+
|
|
18
|
+
const { webpackConfig } = require('../index')
|
|
19
|
+
|
|
20
|
+
expect(webpackConfig.output.path).toEqual(resolve('public', 'packs'))
|
|
21
|
+
expect(webpackConfig.output.publicPath).toEqual('/packs/')
|
|
22
|
+
|
|
23
|
+
expect(webpackConfig).toMatchObject({
|
|
24
|
+
devtool: 'source-map',
|
|
25
|
+
stats: 'normal'
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* test expect, describe, afterAll, beforeEach */
|
|
2
|
+
|
|
3
|
+
const { resolve } = require('path')
|
|
4
|
+
const { chdirTestApp, chdirCwd } = require('../utils/helpers')
|
|
5
|
+
|
|
6
|
+
chdirTestApp()
|
|
7
|
+
|
|
8
|
+
describe('Custom environment', () => {
|
|
9
|
+
afterAll(chdirCwd)
|
|
10
|
+
|
|
11
|
+
describe('webpackConfig', () => {
|
|
12
|
+
beforeEach(() => jest.resetModules())
|
|
13
|
+
|
|
14
|
+
test('should use staging config and default production environment', () => {
|
|
15
|
+
process.env.RAILS_ENV = 'staging'
|
|
16
|
+
delete process.env.NODE_ENV
|
|
17
|
+
|
|
18
|
+
const { webpackConfig } = require('../index')
|
|
19
|
+
|
|
20
|
+
expect(webpackConfig.output.path).toEqual(
|
|
21
|
+
resolve('public', 'packs-staging')
|
|
22
|
+
)
|
|
23
|
+
expect(webpackConfig.output.publicPath).toEqual('/packs-staging/')
|
|
24
|
+
expect(webpackConfig).toMatchObject({
|
|
25
|
+
devtool: 'source-map',
|
|
26
|
+
stats: 'normal'
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* test expect, describe, afterAll, beforeEach */
|
|
2
|
+
|
|
3
|
+
const { resolve } = require('path')
|
|
4
|
+
const { chdirTestApp, chdirCwd } = require('../utils/helpers')
|
|
5
|
+
|
|
6
|
+
chdirTestApp()
|
|
7
|
+
|
|
8
|
+
describe('Test environment', () => {
|
|
9
|
+
afterAll(chdirCwd)
|
|
10
|
+
|
|
11
|
+
describe('toWebpackConfig', () => {
|
|
12
|
+
beforeEach(() => jest.resetModules())
|
|
13
|
+
|
|
14
|
+
test('should use test config and production environment', () => {
|
|
15
|
+
process.env.RAILS_ENV = 'test'
|
|
16
|
+
process.env.NODE_ENV = 'test'
|
|
17
|
+
|
|
18
|
+
const { webpackConfig } = require('../index')
|
|
19
|
+
|
|
20
|
+
expect(webpackConfig.output.path).toEqual(resolve('public', 'packs-test'))
|
|
21
|
+
expect(webpackConfig.output.publicPath).toEqual('/packs-test/')
|
|
22
|
+
expect(webpackConfig.devServer).toEqual(undefined)
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { moduleExists } = require('@shakacode/shakapacker')
|
|
2
|
+
|
|
3
|
+
module.exports = function config(api) {
|
|
4
|
+
const validEnv = ['development', 'test', 'production']
|
|
5
|
+
const currentEnv = api.env()
|
|
6
|
+
const isDevelopmentEnv = api.env('development')
|
|
7
|
+
const isProductionEnv = api.env('production')
|
|
8
|
+
const isTestEnv = api.env('test')
|
|
9
|
+
|
|
10
|
+
if (!validEnv.includes(currentEnv)) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`Please specify a valid NODE_ENV or BABEL_ENV environment variable. Valid values are "development", "test", and "production". Instead, received: "${JSON.stringify(
|
|
13
|
+
currentEnv
|
|
14
|
+
)}".`
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
presets: [
|
|
20
|
+
isTestEnv && ['@babel/preset-env', { targets: { node: 'current' } }],
|
|
21
|
+
(isProductionEnv || isDevelopmentEnv) && [
|
|
22
|
+
'@babel/preset-env',
|
|
23
|
+
{
|
|
24
|
+
useBuiltIns: 'entry',
|
|
25
|
+
corejs: '3.8',
|
|
26
|
+
modules: 'auto',
|
|
27
|
+
bugfixes: true,
|
|
28
|
+
loose: true,
|
|
29
|
+
exclude: ['transform-typeof-symbol']
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
moduleExists('@babel/preset-typescript') && [
|
|
33
|
+
'@babel/preset-typescript',
|
|
34
|
+
{ allExtensions: true, isTSX: true }
|
|
35
|
+
]
|
|
36
|
+
].filter(Boolean),
|
|
37
|
+
plugins: [
|
|
38
|
+
['@babel/plugin-transform-runtime', { helpers: false }]
|
|
39
|
+
].filter(Boolean)
|
|
40
|
+
}
|
|
41
|
+
}
|
data/package/config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { resolve } = require('path')
|
|
2
|
+
const { load } = require('js-yaml')
|
|
3
|
+
const { readFileSync } = require('fs')
|
|
4
|
+
const { merge } = require('webpack-merge')
|
|
5
|
+
const { ensureTrailingSlash } = require('./utils/helpers')
|
|
6
|
+
const { railsEnv } = require('./env')
|
|
7
|
+
const configPath = require('./configPath')
|
|
8
|
+
|
|
9
|
+
const defaultConfigPath = require.resolve('../lib/install/config/webpacker.yml')
|
|
10
|
+
|
|
11
|
+
const getDefaultConfig = () => {
|
|
12
|
+
const defaultConfig = load(readFileSync(defaultConfigPath), 'utf8')
|
|
13
|
+
return defaultConfig[railsEnv] || defaultConfig.production
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const defaults = getDefaultConfig()
|
|
17
|
+
const app = load(readFileSync(configPath), 'utf8')[railsEnv]
|
|
18
|
+
|
|
19
|
+
const config = merge(defaults, app)
|
|
20
|
+
config.outputPath = resolve(config.public_root_path, config.public_output_path)
|
|
21
|
+
|
|
22
|
+
// Ensure that the publicPath includes our asset host so dynamic imports
|
|
23
|
+
// (code-splitting chunks and static assets) load from the CDN instead of a relative path.
|
|
24
|
+
const getPublicPath = () => {
|
|
25
|
+
const rootUrl = ensureTrailingSlash(process.env.WEBPACKER_ASSET_HOST || '/')
|
|
26
|
+
return `${rootUrl}${config.public_output_path}/`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
config.publicPath = getPublicPath()
|
|
30
|
+
config.publicPathWithoutCDN = `/${config.public_output_path}/`
|
|
31
|
+
|
|
32
|
+
module.exports = config
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { isBoolean } = require('./utils/helpers')
|
|
2
|
+
const config = require('./config')
|
|
3
|
+
|
|
4
|
+
const fetch = (key) => {
|
|
5
|
+
const value = process.env[key]
|
|
6
|
+
return isBoolean(value) ? JSON.parse(value) : value
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const devServerConfig = config.dev_server
|
|
10
|
+
|
|
11
|
+
if (devServerConfig) {
|
|
12
|
+
const envPrefix = config.dev_server.env_prefix || 'WEBPACKER_DEV_SERVER'
|
|
13
|
+
|
|
14
|
+
Object.keys(devServerConfig).forEach((key) => {
|
|
15
|
+
const envValue = fetch(`${envPrefix}_${key.toUpperCase()}`)
|
|
16
|
+
if (envValue !== undefined) devServerConfig[key] = envValue
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = devServerConfig || {}
|
data/package/env.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const { load } = require('js-yaml')
|
|
2
|
+
const { readFileSync } = require('fs')
|
|
3
|
+
|
|
4
|
+
const NODE_ENVIRONMENTS = ['development', 'production', 'test']
|
|
5
|
+
const DEFAULT = 'production'
|
|
6
|
+
const configPath = require('./configPath')
|
|
7
|
+
|
|
8
|
+
const railsEnv = process.env.RAILS_ENV
|
|
9
|
+
const rawNodeEnv = process.env.NODE_ENV
|
|
10
|
+
const nodeEnv
|
|
11
|
+
= rawNodeEnv && NODE_ENVIRONMENTS.includes(rawNodeEnv) ? rawNodeEnv : DEFAULT
|
|
12
|
+
const isProduction = nodeEnv === 'production'
|
|
13
|
+
const isDevelopment = nodeEnv === 'development'
|
|
14
|
+
|
|
15
|
+
const config = load(readFileSync(configPath), 'utf8')
|
|
16
|
+
const availableEnvironments = Object.keys(config).join('|')
|
|
17
|
+
const regex = new RegExp(`^(${availableEnvironments})$`, 'g')
|
|
18
|
+
|
|
19
|
+
const runningWebpackDevServer = process.env.WEBPACK_SERVE === 'true'
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
railsEnv: railsEnv && railsEnv.match(regex) ? railsEnv : DEFAULT,
|
|
23
|
+
nodeEnv,
|
|
24
|
+
isProduction,
|
|
25
|
+
isDevelopment,
|
|
26
|
+
runningWebpackDevServer
|
|
27
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* global test expect, describe, afterAll, beforeEach */
|
|
2
|
+
|
|
3
|
+
// environment.js expects to find config/webpacker.yml and resolved modules from
|
|
4
|
+
// the root of a Rails project
|
|
5
|
+
|
|
6
|
+
const { chdirTestApp, chdirCwd } = require('../../utils/helpers')
|
|
7
|
+
|
|
8
|
+
chdirTestApp()
|
|
9
|
+
|
|
10
|
+
const { resolve } = require('path')
|
|
11
|
+
const rules = require('../../rules')
|
|
12
|
+
const baseConfig = require('../base')
|
|
13
|
+
|
|
14
|
+
describe('Base config', () => {
|
|
15
|
+
afterAll(chdirCwd)
|
|
16
|
+
|
|
17
|
+
describe('config', () => {
|
|
18
|
+
test('should return entry', () => {
|
|
19
|
+
expect(baseConfig.entry.application).toEqual(
|
|
20
|
+
resolve('app', 'packs', 'entrypoints', 'application.js')
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('should return multi file entry points', () => {
|
|
25
|
+
expect(baseConfig.entry.multi_entry.sort()).toEqual([
|
|
26
|
+
resolve('app', 'packs', 'entrypoints', 'multi_entry.css'),
|
|
27
|
+
resolve('app', 'packs', 'entrypoints', 'multi_entry.js')
|
|
28
|
+
])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('should return output', () => {
|
|
32
|
+
expect(baseConfig.output.filename).toEqual('js/[name].js')
|
|
33
|
+
expect(baseConfig.output.chunkFilename).toEqual(
|
|
34
|
+
'js/[name].chunk.js'
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('should return default loader rules for each file in config/loaders', () => {
|
|
39
|
+
const defaultRules = Object.keys(rules)
|
|
40
|
+
const configRules = baseConfig.module.rules
|
|
41
|
+
|
|
42
|
+
expect(defaultRules.length).toEqual(3)
|
|
43
|
+
expect(configRules.length).toEqual(3)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('should return default plugins', () => {
|
|
47
|
+
expect(baseConfig.plugins.length).toEqual(2)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('should return default resolveLoader', () => {
|
|
51
|
+
expect(baseConfig.resolveLoader.modules).toEqual(['node_modules'])
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('should return default resolve.modules with additions', () => {
|
|
55
|
+
expect(baseConfig.resolve.modules).toEqual([
|
|
56
|
+
resolve('app', 'packs'),
|
|
57
|
+
resolve('app/assets'),
|
|
58
|
+
resolve('/etc/yarn'),
|
|
59
|
+
resolve('some.config.js'),
|
|
60
|
+
resolve('app/elm'),
|
|
61
|
+
'node_modules'
|
|
62
|
+
])
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('returns plugins property as Array', () => {
|
|
66
|
+
expect(baseConfig.plugins).toBeInstanceOf(Array)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
})
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/* eslint global-require: 0 */
|
|
2
|
+
/* eslint import/no-dynamic-require: 0 */
|
|
3
|
+
|
|
4
|
+
const { basename, dirname, join, relative, resolve } = require('path')
|
|
5
|
+
const extname = require('path-complete-extname')
|
|
6
|
+
const PnpWebpackPlugin = require('pnp-webpack-plugin')
|
|
7
|
+
const { sync: globSync } = require('glob')
|
|
8
|
+
const WebpackAssetsManifest = require('webpack-assets-manifest')
|
|
9
|
+
const webpack = require('webpack')
|
|
10
|
+
const rules = require('../rules')
|
|
11
|
+
const { isProduction } = require('../env')
|
|
12
|
+
const config = require('../config')
|
|
13
|
+
const { moduleExists } = require('../utils/helpers')
|
|
14
|
+
|
|
15
|
+
const getEntryObject = () => {
|
|
16
|
+
const entries = {}
|
|
17
|
+
const rootPath = join(config.source_path, config.source_entry_path)
|
|
18
|
+
|
|
19
|
+
globSync(`${rootPath}/*.*`).forEach((path) => {
|
|
20
|
+
const namespace = relative(join(rootPath), dirname(path))
|
|
21
|
+
const name = join(namespace, basename(path, extname(path)))
|
|
22
|
+
let assetPaths = resolve(path)
|
|
23
|
+
|
|
24
|
+
// Allows for multiple filetypes per entry (https://webpack.js.org/guides/entry-advanced/)
|
|
25
|
+
// Transforms the config object value to an array with all values under the same name
|
|
26
|
+
let previousPaths = entries[name]
|
|
27
|
+
if (previousPaths) {
|
|
28
|
+
previousPaths = Array.isArray(previousPaths)
|
|
29
|
+
? previousPaths
|
|
30
|
+
: [previousPaths]
|
|
31
|
+
previousPaths.push(assetPaths)
|
|
32
|
+
assetPaths = previousPaths
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
entries[name] = assetPaths
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
return entries
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const getModulePaths = () => {
|
|
42
|
+
const result = [resolve(config.source_path)]
|
|
43
|
+
|
|
44
|
+
if (config.additional_paths) {
|
|
45
|
+
config.additional_paths.forEach((path) => result.push(resolve(path)))
|
|
46
|
+
}
|
|
47
|
+
result.push('node_modules')
|
|
48
|
+
|
|
49
|
+
return result
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const getPlugins = () => {
|
|
53
|
+
const plugins = [
|
|
54
|
+
new webpack.EnvironmentPlugin(process.env),
|
|
55
|
+
new WebpackAssetsManifest({
|
|
56
|
+
entrypoints: true,
|
|
57
|
+
writeToDisk: true,
|
|
58
|
+
output: 'manifest.json',
|
|
59
|
+
entrypointsUseAssets: true,
|
|
60
|
+
publicPath: true
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
if (moduleExists('css-loader') && moduleExists('mini-css-extract-plugin')) {
|
|
65
|
+
const hash = isProduction ? '-[contenthash:8]' : ''
|
|
66
|
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
67
|
+
plugins.push(
|
|
68
|
+
new MiniCssExtractPlugin({
|
|
69
|
+
filename: `css/[name]${hash}.css`,
|
|
70
|
+
chunkFilename: `css/[id]${hash}.css`
|
|
71
|
+
})
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return plugins
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Don't use contentHash except for production for performance
|
|
79
|
+
// https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
|
|
80
|
+
const hash = isProduction ? '-[contenthash]' : ''
|
|
81
|
+
module.exports = {
|
|
82
|
+
mode: 'production',
|
|
83
|
+
output: {
|
|
84
|
+
filename: `js/[name]${hash}.js`,
|
|
85
|
+
chunkFilename: `js/[name]${hash}.chunk.js`,
|
|
86
|
+
|
|
87
|
+
// https://webpack.js.org/configuration/output/#outputhotupdatechunkfilename
|
|
88
|
+
hotUpdateChunkFilename: 'js/[id].[fullhash].hot-update.js',
|
|
89
|
+
path: config.outputPath,
|
|
90
|
+
publicPath: config.publicPath
|
|
91
|
+
},
|
|
92
|
+
entry: getEntryObject(),
|
|
93
|
+
resolve: {
|
|
94
|
+
extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.coffee'],
|
|
95
|
+
modules: getModulePaths(),
|
|
96
|
+
plugins: [PnpWebpackPlugin]
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
plugins: getPlugins(),
|
|
100
|
+
|
|
101
|
+
resolveLoader: {
|
|
102
|
+
modules: ['node_modules'],
|
|
103
|
+
plugins: [PnpWebpackPlugin.moduleLoader(module)]
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
optimization: {
|
|
107
|
+
splitChunks: { chunks: 'all' },
|
|
108
|
+
|
|
109
|
+
runtimeChunk: 'single'
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
module: {
|
|
113
|
+
strictExportPresence: true,
|
|
114
|
+
rules
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const { merge } = require('webpack-merge')
|
|
2
|
+
|
|
3
|
+
const baseConfig = require('./base')
|
|
4
|
+
const devServer = require('../dev_server')
|
|
5
|
+
const { runningWebpackDevServer } = require('../env')
|
|
6
|
+
|
|
7
|
+
const { outputPath: contentBase, publicPath } = require('../config')
|
|
8
|
+
|
|
9
|
+
let devConfig = {
|
|
10
|
+
mode: 'development',
|
|
11
|
+
devtool: 'cheap-module-source-map'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (runningWebpackDevServer) {
|
|
15
|
+
const liveReload = devServer.live_reload !== undefined ? devServer.live_reload : !devServer.hmr
|
|
16
|
+
|
|
17
|
+
const devServerConfig = {
|
|
18
|
+
devMiddleware: {
|
|
19
|
+
publicPath
|
|
20
|
+
},
|
|
21
|
+
compress: devServer.compress,
|
|
22
|
+
allowedHosts: devServer.allowed_hosts,
|
|
23
|
+
host: devServer.host,
|
|
24
|
+
port: devServer.port,
|
|
25
|
+
https: devServer.https,
|
|
26
|
+
hot: devServer.hmr,
|
|
27
|
+
liveReload,
|
|
28
|
+
historyApiFallback: { disableDotRule: true },
|
|
29
|
+
headers: devServer.headers,
|
|
30
|
+
static: {
|
|
31
|
+
publicPath: contentBase
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (devServer.static) {
|
|
36
|
+
devServerConfig.static = { ...devServerConfig.static, ...devServer.static }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (devServer.client) {
|
|
40
|
+
devServerConfig.client = devServer.client
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
devConfig = merge(devConfig, {
|
|
44
|
+
stats: {
|
|
45
|
+
colors: true,
|
|
46
|
+
entrypoints: false,
|
|
47
|
+
errorDetails: true,
|
|
48
|
+
modules: false,
|
|
49
|
+
moduleTrace: false
|
|
50
|
+
},
|
|
51
|
+
devServer: devServerConfig
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = merge(baseConfig, devConfig)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* eslint global-require: 0 */
|
|
2
|
+
/* eslint import/no-dynamic-require: 0 */
|
|
3
|
+
|
|
4
|
+
const { merge } = require('webpack-merge')
|
|
5
|
+
const CompressionPlugin = require('compression-webpack-plugin')
|
|
6
|
+
const TerserPlugin = require('terser-webpack-plugin')
|
|
7
|
+
const baseConfig = require('./base')
|
|
8
|
+
const { moduleExists } = require('../utils/helpers')
|
|
9
|
+
|
|
10
|
+
const getPlugins = () => {
|
|
11
|
+
const plugins = []
|
|
12
|
+
|
|
13
|
+
plugins.push(
|
|
14
|
+
new CompressionPlugin({
|
|
15
|
+
filename: '[path][base].gz[query]',
|
|
16
|
+
algorithm: 'gzip',
|
|
17
|
+
test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
|
|
18
|
+
})
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if ('brotli' in process.versions) {
|
|
22
|
+
plugins.push(
|
|
23
|
+
new CompressionPlugin({
|
|
24
|
+
filename: '[path][base].br[query]',
|
|
25
|
+
algorithm: 'brotliCompress',
|
|
26
|
+
test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
|
|
27
|
+
})
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return plugins
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const tryCssMinimizer = () => {
|
|
35
|
+
if (
|
|
36
|
+
moduleExists('css-loader') &&
|
|
37
|
+
moduleExists('css-minimizer-webpack-plugin')
|
|
38
|
+
) {
|
|
39
|
+
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
|
|
40
|
+
return new CssMinimizerPlugin()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const productionConfig = {
|
|
47
|
+
devtool: 'source-map',
|
|
48
|
+
stats: 'normal',
|
|
49
|
+
bail: true,
|
|
50
|
+
plugins: getPlugins(),
|
|
51
|
+
optimization: {
|
|
52
|
+
minimizer: [
|
|
53
|
+
tryCssMinimizer(),
|
|
54
|
+
new TerserPlugin({
|
|
55
|
+
parallel: Number.parseInt(process.env.WEBPACKER_PARALLEL, 10) || true,
|
|
56
|
+
terserOptions: {
|
|
57
|
+
parse: {
|
|
58
|
+
// Let terser parse ecma 8 code but always output
|
|
59
|
+
// ES5 compliant code for older browsers
|
|
60
|
+
ecma: 8
|
|
61
|
+
},
|
|
62
|
+
compress: {
|
|
63
|
+
ecma: 5,
|
|
64
|
+
warnings: false,
|
|
65
|
+
comparisons: false
|
|
66
|
+
},
|
|
67
|
+
mangle: { safari10: true },
|
|
68
|
+
output: {
|
|
69
|
+
ecma: 5,
|
|
70
|
+
comments: false,
|
|
71
|
+
ascii_only: true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
].filter(Boolean)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = merge(baseConfig, productionConfig)
|
data/package/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* eslint global-require: 0 */
|
|
2
|
+
/* eslint import/no-dynamic-require: 0 */
|
|
3
|
+
|
|
4
|
+
const webpackMerge = require('webpack-merge')
|
|
5
|
+
const { resolve } = require('path')
|
|
6
|
+
const { existsSync } = require('fs')
|
|
7
|
+
const baseConfig = require('./environments/base')
|
|
8
|
+
const rules = require('./rules')
|
|
9
|
+
const config = require('./config')
|
|
10
|
+
const devServer = require('./dev_server')
|
|
11
|
+
const env = require('./env')
|
|
12
|
+
const { moduleExists, canProcess } = require('./utils/helpers')
|
|
13
|
+
const inliningCss = require('./inliningCss')
|
|
14
|
+
|
|
15
|
+
const webpackConfig = () => {
|
|
16
|
+
const { nodeEnv } = env
|
|
17
|
+
const path = resolve(__dirname, 'environments', `${nodeEnv}.js`)
|
|
18
|
+
const environmentConfig = existsSync(path) ? require(path) : baseConfig
|
|
19
|
+
return environmentConfig
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
config,
|
|
24
|
+
devServer,
|
|
25
|
+
webpackConfig: webpackConfig(),
|
|
26
|
+
baseConfig,
|
|
27
|
+
env,
|
|
28
|
+
rules,
|
|
29
|
+
moduleExists,
|
|
30
|
+
canProcess,
|
|
31
|
+
inliningCss,
|
|
32
|
+
...webpackMerge
|
|
33
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const { resolve } = require('path')
|
|
2
|
+
const { realpathSync } = require('fs')
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
source_path: sourcePath,
|
|
6
|
+
additional_paths: additionalPaths
|
|
7
|
+
} = require('../config')
|
|
8
|
+
const { isProduction } = require('../env')
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
|
|
12
|
+
include: [sourcePath, ...additionalPaths].map((p) => {
|
|
13
|
+
try {
|
|
14
|
+
return realpathSync(p)
|
|
15
|
+
} catch (e) {
|
|
16
|
+
return resolve(p)
|
|
17
|
+
}
|
|
18
|
+
}),
|
|
19
|
+
exclude: /node_modules/,
|
|
20
|
+
use: [
|
|
21
|
+
{
|
|
22
|
+
loader: require.resolve('babel-loader'),
|
|
23
|
+
options: {
|
|
24
|
+
cacheDirectory: true,
|
|
25
|
+
cacheCompression: isProduction,
|
|
26
|
+
compact: isProduction
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|