shakapacker 6.3.0.pre.rc.1 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -3
- data/Gemfile.lock +1 -1
- data/README.md +16 -2
- data/docs/react.md +262 -0
- data/lib/install/config/webpacker.yml +4 -0
- data/lib/webpacker/base_strategy.rb +24 -0
- data/lib/webpacker/compiler.rb +6 -51
- data/lib/webpacker/compiler_strategy.rb +20 -0
- data/lib/webpacker/configuration.rb +4 -0
- data/lib/webpacker/digest_strategy.rb +59 -0
- data/lib/webpacker/instance.rb +4 -0
- data/lib/webpacker/mtime_strategy.rb +40 -0
- data/lib/webpacker/version.rb +1 -1
- data/package/rules/file.js +2 -2
- data/package.json +3 -3
- data/test/compiler_strategy_test.rb +27 -0
- data/test/compiler_test.rb +27 -30
- data/test/digest_strategy_test.rb +33 -0
- data/test/mtime_strategy_test.rb +42 -0
- metadata +16 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ceac7ca1c43918c99f5c5f50eec4f34fc591ef9de90bac0f2a35c7d0e7c4cc69
|
4
|
+
data.tar.gz: 4f571c49df398b3ff2dfd3faf476908c4492b361a9ebaf64d4c91e4c6074df5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bcccce7cc22a42f20ac8738904a97d8288abb862a5d0c98e487393450d60a6a703559aa1b3add2f70f5211643fb02769ca16ef118cee5870f7de580a07cfcbb
|
7
|
+
data.tar.gz: 6f27881ee63c1cc94c416c9d59e8354a3425707e055b035bb89d1da86905c2ae876e3d329da59f9015f29f3219f716f042dccabaf563a01cf327a0d8be89b41e
|
data/CHANGELOG.md
CHANGED
@@ -8,7 +8,17 @@ Changes since last non-beta release.
|
|
8
8
|
|
9
9
|
*Please add entries here for your pull requests that are not yet released.*
|
10
10
|
|
11
|
-
## [v6.3.0
|
11
|
+
## [v6.3.0] - May 19, 2022
|
12
|
+
|
13
|
+
### Improved
|
14
|
+
- Add ability to configure usage of either last modified timestamp and digest strategies when checking asset freshness. [PR 112](https://github.com/shakacode/shakapacker/pull/112) by [tomdracz](https://github.com/tomdracz).
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
- On Windows CSS urls no longer contain backslashes resulting in 404 errors. [PR 115](https://github.com/shakacode/shakapacker/pull/115) by [daniel-rikowski](https://github.com/daniel-rikowski).
|
18
|
+
|
19
|
+
## [v6.3.0-rc.1] - April 24, 2022
|
20
|
+
|
21
|
+
Note: [Rubygem is 6.3.0.pre.rc.1](https://rubygems.org/gems/shakapacker/versions/6.3.0.pre.rc.1) and [NPM is 6.3.0-rc.1](https://www.npmjs.com/package/shakapacker/v/6.3.0-rc.1).
|
12
22
|
|
13
23
|
### Changed
|
14
24
|
- Remove Loose mode from the default @babel-preset/env configuration. [PR 107](https://github.com/shakacode/shakapacker/pull/107) by [Jeremy Liberman](https://github.com/MrLeebo).
|
@@ -115,8 +125,9 @@ Changes since last non-beta release.
|
|
115
125
|
## v5.4.3 and prior changes from rails/webpacker
|
116
126
|
See [CHANGELOG.md in rails/webpacker (up to v5.4.3)](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)
|
117
127
|
|
118
|
-
[Unreleased]: https://github.com/shakacode/shakapacker/compare/v6.3.0
|
119
|
-
[v6.3.0
|
128
|
+
[Unreleased]: https://github.com/shakacode/shakapacker/compare/v6.3.0...master
|
129
|
+
[v6.3.0]: https://github.com/shakacode/shakapacker/compare/v6.3.0-rc.1...v6.3.0
|
130
|
+
[v6.3.0-rc.1]: https://github.com/shakacode/shakapacker/compare/v6.2.1...v6.3.0-rc.1
|
120
131
|
[v6.2.1]: https://github.com/shakacode/shakapacker/compare/v6.2.0...v6.2.1
|
121
132
|
[v6.2.0]: https://github.com/shakacode/shakapacker/compare/v6.1.1...v6.2.0
|
122
133
|
[v6.1.1]: https://github.com/shakacode/shakapacker/compare/v6.1.0...v6.1.1
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -62,6 +62,7 @@ Discussion forum and Slack to discuss debugging and troubleshooting tips. Please
|
|
62
62
|
- [Other frameworks](#other-frameworks)
|
63
63
|
- [Custom Rails environments](#custom-rails-environments)
|
64
64
|
- [Upgrading](#upgrading)
|
65
|
+
- [Compiler strategies](#compiler-strategies)
|
65
66
|
- [Paths](#paths)
|
66
67
|
- [Additional paths](#additional-paths)
|
67
68
|
- [Deployment](#deployment)
|
@@ -431,7 +432,9 @@ Webpacker out of the box supports JS and static assets (fonts, images etc.) comp
|
|
431
432
|
|
432
433
|
#### React
|
433
434
|
|
434
|
-
See
|
435
|
+
See here for detailed instructions on how to [configure Shakapacker to bundle a React app](./docs/react.md) (with optional HMR).
|
436
|
+
|
437
|
+
See also [Customizing Babel Config](./docs/customizing_babel_config.md) for an example React configuration.
|
435
438
|
|
436
439
|
#### Typescript
|
437
440
|
...if you are using typescript, update your `tsconfig.json`
|
@@ -671,6 +674,17 @@ yarn add shakapacker@next
|
|
671
674
|
|
672
675
|
Also, consult the [CHANGELOG](./CHANGELOG.md) for additional upgrade links.
|
673
676
|
|
677
|
+
### Compiler strategies
|
678
|
+
|
679
|
+
Shakapacker ships with two different strategies that are used to determine whether assets need recompilation.
|
680
|
+
|
681
|
+
- `digest` - This strategy calculates SHA1 digest of files in your watched paths (see below). The calculated digest is then stored in a temp file. To check whether the assets need to be recompiled, Shakapacker calculates the SHA1 of the watched files and compares it with the one stored. If the digests are equal, no recompilation occurs. If the digests are different or the temp file is missing, files are recompiled.
|
682
|
+
- `mtime` - This strategy looks at last modified at timestamps of both files AND directories in your watched paths. The timestamp of the most recent file or directory is then compared with the timestamp of `manifest.json` file generated. If the manifest file timestamp is newer than one of the most recently modified file or directory in the watched paths, no recompilation occurs. If the manifest file is order, files are recompiled.
|
683
|
+
|
684
|
+
`mtime` strategy is generally faster than the `digest` one, but it requires stable timestamps, this makes it perfect for development environment. In production or CI environments, the `digest` strategy is more suitable, unless you are using incremental builds or caching and can guarantee that the timestamps will not change after e.g. cache restore.
|
685
|
+
|
686
|
+
You can control what strategy is used by `compiler_strategy` option in `webpacker.yml` config file. By default `mtime` strategy is used in development environment, `digest` is used elsewhere.
|
687
|
+
|
674
688
|
### Paths
|
675
689
|
|
676
690
|
By default, Webpacker ships with simple conventions for where the JavaScript app files and compiled webpack bundles will go in your Rails app. All these options are configurable from `config/webpacker.yml` file.
|
@@ -718,7 +732,7 @@ import 'images/rails.png'
|
|
718
732
|
|
719
733
|
**Note:** Please be careful when adding paths here otherwise it will make the compilation slow, consider adding specific paths instead of whole parent directory if you just need to reference one or two modules
|
720
734
|
|
721
|
-
**Also note:** While importing assets living outside your `source_path` defined in webpacker.yml (like, for instance, assets under `app/assets`) from within your packs using _relative_ paths like `import '../../assets/javascripts/file.js'` will work in development, Webpacker won't recompile the bundle in production unless a file that lives in one of it's watched paths has changed (check out `Webpacker::
|
735
|
+
**Also note:** While importing assets living outside your `source_path` defined in webpacker.yml (like, for instance, assets under `app/assets`) from within your packs using _relative_ paths like `import '../../assets/javascripts/file.js'` will work in development, Webpacker won't recompile the bundle in production unless a file that lives in one of it's watched paths has changed (check out `Webpacker::MtimeStrategy#latest_modified_timestamp` or `Webpacker::DigestStrategy#watched_files_digest` depending on strategy configured by `compiler_strategy` option in `webpacker.yml`). That's why you'd need to add `app/assets` to the additional_paths as stated above and use `import 'javascripts/file.js'` instead.
|
722
736
|
|
723
737
|
|
724
738
|
## Deployment
|
data/docs/react.md
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
# React Integration
|
2
|
+
|
3
|
+
These steps describe how to create a Rails/React app, using Shakapacker as the bundler.
|
4
|
+
|
5
|
+
Before starting, ensure that you have Yarn installed, for example:
|
6
|
+
|
7
|
+
```shell
|
8
|
+
npm i -g yarn
|
9
|
+
```
|
10
|
+
|
11
|
+
## Basic Setup
|
12
|
+
|
13
|
+
Create a new Rails app as per the [installation instructions in the README](https://github.com/shakacode/shakapacker#installation).
|
14
|
+
|
15
|
+
Add React, as well as the necessary libraries to enable CSS support in your application:
|
16
|
+
|
17
|
+
```shell
|
18
|
+
yarn add react react-dom @babel/preset-react
|
19
|
+
yarn add css-loader style-loader mini-css-extract-plugin css-minimizer-webpack-plugin
|
20
|
+
```
|
21
|
+
|
22
|
+
Update the Babel configuration in the `package.json` file:
|
23
|
+
|
24
|
+
```diff
|
25
|
+
"babel": {
|
26
|
+
"presets": [
|
27
|
+
"./node_modules/shakapacker/package/babel/preset.js",
|
28
|
+
+ "@babel/preset-react"
|
29
|
+
]
|
30
|
+
},
|
31
|
+
```
|
32
|
+
|
33
|
+
And that's it. You can now create a React app using `app/javascript/application.js` as your entry point.
|
34
|
+
|
35
|
+
## Enabling Hot Module Replacement (HMR)
|
36
|
+
|
37
|
+
With HMR enabled, Shakapacker will automatically update only that part of the page that changed when it detects changes in your project files. This has the nice advantage of preserving your app’s state.
|
38
|
+
|
39
|
+
To enable HMR in a React app, proceed as follows:.
|
40
|
+
|
41
|
+
In `config/webpacker.yml` set `hmr` is set to `true`.
|
42
|
+
|
43
|
+
Install the [react-refresh](https://www.npmjs.com/package/react-refresh) package, as well as [@pmmmwh/react-refresh-webpack-plugin](https://www.npmjs.com/package/@pmmmwh/react-refresh-webpack-plugin):
|
44
|
+
|
45
|
+
```shell
|
46
|
+
yarn add --dev react-refresh @pmmmwh/react-refresh-webpack-plugin
|
47
|
+
```
|
48
|
+
|
49
|
+
Alter `config/webpack/webpack.config.js` like so:
|
50
|
+
|
51
|
+
```js
|
52
|
+
const { webpackConfig, inliningCss } = require('shakapacker');
|
53
|
+
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
54
|
+
const isDevelopment = process.env.NODE_ENV !== 'production';
|
55
|
+
|
56
|
+
if (isDevelopment && inliningCss) {
|
57
|
+
webpackConfig.plugins.push(
|
58
|
+
new ReactRefreshWebpackPlugin({
|
59
|
+
overlay: {
|
60
|
+
sockPort: webpackConfig.devServer.port,
|
61
|
+
},
|
62
|
+
})
|
63
|
+
);
|
64
|
+
}
|
65
|
+
|
66
|
+
module.exports = webpackConfig;
|
67
|
+
```
|
68
|
+
|
69
|
+
This applies the plugin to the webpack configuration.
|
70
|
+
|
71
|
+
Delete the Babel configuration from `package.json`:
|
72
|
+
|
73
|
+
```diff
|
74
|
+
- "babel": {
|
75
|
+
- "presets": [
|
76
|
+
- "./node_modules/shakapacker/package/babel/preset.js",
|
77
|
+
- "@babel/preset-react"
|
78
|
+
- ]
|
79
|
+
- },
|
80
|
+
```
|
81
|
+
|
82
|
+
Then create a `babel.config.js` file in the root of project and add the following:
|
83
|
+
|
84
|
+
```js
|
85
|
+
module.exports = function (api) {
|
86
|
+
const defaultConfigFunc = require('shakapacker/package/babel/preset.js')
|
87
|
+
const resultConfig = defaultConfigFunc(api)
|
88
|
+
const isDevelopmentEnv = api.env('development')
|
89
|
+
const isProductionEnv = api.env('production')
|
90
|
+
const isTestEnv = api.env('test')
|
91
|
+
|
92
|
+
const changesOnDefault = {
|
93
|
+
presets: [
|
94
|
+
[
|
95
|
+
'@babel/preset-react',
|
96
|
+
{
|
97
|
+
development: isDevelopmentEnv || isTestEnv,
|
98
|
+
useBuiltIns: true
|
99
|
+
}
|
100
|
+
]
|
101
|
+
].filter(Boolean),
|
102
|
+
plugins: [
|
103
|
+
isProductionEnv && ['babel-plugin-transform-react-remove-prop-types',
|
104
|
+
{
|
105
|
+
removeImport: true
|
106
|
+
}
|
107
|
+
],
|
108
|
+
process.env.WEBPACK_SERVE && 'react-refresh/babel'
|
109
|
+
].filter(Boolean),
|
110
|
+
}
|
111
|
+
|
112
|
+
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]
|
113
|
+
resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins ]
|
114
|
+
|
115
|
+
return resultConfig
|
116
|
+
}
|
117
|
+
```
|
118
|
+
|
119
|
+
This is taken from the [sample React Babel config](https://github.com/jameshibbard/shakapacker/blob/master/docs/customizing_babel_config.md#react-configuration).
|
120
|
+
|
121
|
+
HMR for your React app is now enabled. 🚀
|
122
|
+
|
123
|
+
## A Basic Demo App
|
124
|
+
|
125
|
+
To test that all of the above is working, you can follow these instructions to create a basic React app using Shakapacker.
|
126
|
+
|
127
|
+
1. Create a new Rails app:
|
128
|
+
```shell
|
129
|
+
rails new myapp --skip-javascript
|
130
|
+
cd myapp
|
131
|
+
bundle add shakapacker --strict
|
132
|
+
./bin/bundle install
|
133
|
+
./bin/rails webpacker:install
|
134
|
+
yarn add react react-dom @babel/preset-react
|
135
|
+
yarn add css-loader style-loader mini-css-extract-plugin css-minimizer-webpack-plugin
|
136
|
+
```
|
137
|
+
|
138
|
+
2. Generate a controller
|
139
|
+
```shell
|
140
|
+
rails g controller site index
|
141
|
+
echo '<div id="root"></div>' > app/views/site/index.html.erb
|
142
|
+
```
|
143
|
+
|
144
|
+
3. Create a CSS file and a React component:
|
145
|
+
```shell
|
146
|
+
touch app/javascript/App.css app/javascript/App.js
|
147
|
+
```
|
148
|
+
|
149
|
+
4. Edit `app/javascript/application.js` like so:
|
150
|
+
```jsx
|
151
|
+
import React from 'react';
|
152
|
+
import { createRoot } from 'react-dom/client';
|
153
|
+
import HelloMessage from './App';
|
154
|
+
|
155
|
+
const container = document.getElementById('root');
|
156
|
+
const root = createRoot(container);
|
157
|
+
|
158
|
+
document.addEventListener('DOMContentLoaded', () => {
|
159
|
+
root.render(<HelloMessage name="World" />);
|
160
|
+
});
|
161
|
+
```
|
162
|
+
|
163
|
+
5. Add the following to `app/javascript/App.js`:
|
164
|
+
```jsx
|
165
|
+
import React from 'react';
|
166
|
+
import 'App.css';
|
167
|
+
const HelloMessage = ({ name }) => <h1>Hello, {name}!</h1>;
|
168
|
+
export default HelloMessage;
|
169
|
+
```
|
170
|
+
|
171
|
+
6. Add the following to `app/javascript/App.css`:
|
172
|
+
```css
|
173
|
+
h1 { color: blue; }
|
174
|
+
```
|
175
|
+
|
176
|
+
7. Enable HMR in config/webpacker.yml:
|
177
|
+
```shell
|
178
|
+
hmr: true
|
179
|
+
```
|
180
|
+
|
181
|
+
8. Install the [react-refresh](https://www.npmjs.com/package/react-refresh) package, as well as [@pmmmwh/react-refresh-webpack-plugin](https://www.npmjs.com/package/@pmmmwh/react-refresh-webpack-plugin):
|
182
|
+
|
183
|
+
```shell
|
184
|
+
yarn add --dev react-refresh @pmmmwh/react-refresh-webpack-plugin
|
185
|
+
```
|
186
|
+
|
187
|
+
9. Alter `config/webpack/webpack.config.js` like so:
|
188
|
+
|
189
|
+
```js
|
190
|
+
const { webpackConfig, inliningCss } = require('shakapacker');
|
191
|
+
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
192
|
+
const isDevelopment = process.env.NODE_ENV !== 'production';
|
193
|
+
|
194
|
+
if (isDevelopment && inliningCss) {
|
195
|
+
webpackConfig.plugins.push(
|
196
|
+
new ReactRefreshWebpackPlugin({
|
197
|
+
overlay: {
|
198
|
+
sockPort: webpackConfig.devServer.port,
|
199
|
+
},
|
200
|
+
})
|
201
|
+
);
|
202
|
+
}
|
203
|
+
|
204
|
+
module.exports = webpackConfig;
|
205
|
+
```
|
206
|
+
|
207
|
+
10. Remove the Babel configuration from `package.json`
|
208
|
+
```diff
|
209
|
+
- "babel": {
|
210
|
+
- "presets": [
|
211
|
+
- "./node_modules/shakapacker/package/babel/preset.js"
|
212
|
+
- ]
|
213
|
+
- },
|
214
|
+
```
|
215
|
+
|
216
|
+
11. Create a `babel.config.js` file in the project root and add the following [sample code](https://github.com/shakacode/shakapacker/blob/master/docs/customizing_babel_config.md#react-configuration):
|
217
|
+
```js
|
218
|
+
module.exports = function (api) {
|
219
|
+
const defaultConfigFunc = require('shakapacker/package/babel/preset.js')
|
220
|
+
const resultConfig = defaultConfigFunc(api)
|
221
|
+
const isDevelopmentEnv = api.env('development')
|
222
|
+
const isProductionEnv = api.env('production')
|
223
|
+
const isTestEnv = api.env('test')
|
224
|
+
|
225
|
+
const changesOnDefault = {
|
226
|
+
presets: [
|
227
|
+
[
|
228
|
+
'@babel/preset-react',
|
229
|
+
{
|
230
|
+
development: isDevelopmentEnv || isTestEnv,
|
231
|
+
useBuiltIns: true
|
232
|
+
}
|
233
|
+
]
|
234
|
+
].filter(Boolean),
|
235
|
+
plugins: [
|
236
|
+
isProductionEnv && ['babel-plugin-transform-react-remove-prop-types',
|
237
|
+
{
|
238
|
+
removeImport: true
|
239
|
+
}
|
240
|
+
],
|
241
|
+
process.env.WEBPACK_SERVE && 'react-refresh/babel'
|
242
|
+
].filter(Boolean),
|
243
|
+
}
|
244
|
+
|
245
|
+
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]
|
246
|
+
resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins ]
|
247
|
+
|
248
|
+
return resultConfig
|
249
|
+
}
|
250
|
+
```
|
251
|
+
|
252
|
+
9. Start the Rails server and the webpack-dev-server in separate console windows:
|
253
|
+
```shell
|
254
|
+
rails s
|
255
|
+
./bin/webpacker-dev-server
|
256
|
+
```
|
257
|
+
|
258
|
+
10. Hit: <http://localhost:3000/site/index>
|
259
|
+
|
260
|
+
11. Edit either the React component at `app/javascript/App.js` or the CSS file at `app/javascript/App.css` and observe the HMR goodness.
|
261
|
+
|
262
|
+
Note that HMR will not work if you edit `app/javascript/application.js` and you experience a full refresh with a warning in the console. For more info on this, see here: https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/177
|
@@ -26,9 +26,13 @@ default: &default
|
|
26
26
|
# Set to true to enable check for matching versions of shakapacker gem and NPM package - will raise an error if there is a mismatch or wildcard versioning is used
|
27
27
|
ensure_consistent_versioning: false
|
28
28
|
|
29
|
+
# Select whether the compiler will use SHA digest ('digest' option) or most most recent modified timestamp ('mtime') to determine freshness
|
30
|
+
compiler_strategy: digest
|
31
|
+
|
29
32
|
development:
|
30
33
|
<<: *default
|
31
34
|
compile: true
|
35
|
+
compiler_strategy: mtime
|
32
36
|
|
33
37
|
# Reference: https://webpack.js.org/configuration/dev-server/
|
34
38
|
dev_server:
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Webpacker
|
2
|
+
class BaseStrategy
|
3
|
+
def initialize
|
4
|
+
@config = Webpacker.config
|
5
|
+
end
|
6
|
+
|
7
|
+
def after_compile_hook
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :config
|
14
|
+
|
15
|
+
def default_watched_paths
|
16
|
+
[
|
17
|
+
*config.additional_paths.map { |path| "#{path}{,/**/*}" },
|
18
|
+
"#{config.source_path}{,/**/*}",
|
19
|
+
"yarn.lock", "package.json",
|
20
|
+
"config/webpack{,/**/*}"
|
21
|
+
].freeze
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/webpacker/compiler.rb
CHANGED
@@ -1,17 +1,13 @@
|
|
1
1
|
require "open3"
|
2
|
+
require "webpacker/compiler_strategy"
|
2
3
|
|
3
4
|
class Webpacker::Compiler
|
4
|
-
# Additional paths that test compiler needs to watch
|
5
|
-
# Webpacker::Compiler.watched_paths << 'bower_components'
|
6
|
-
#
|
7
|
-
# Deprecated. Use additional_paths in the YAML configuration instead.
|
8
|
-
cattr_accessor(:watched_paths) { [] }
|
9
|
-
|
10
5
|
# Additional environment variables that the compiler is being run with
|
11
6
|
# Webpacker::Compiler.env['FRONTEND_API_KEY'] = 'your_secret_key'
|
12
7
|
cattr_accessor(:env) { {} }
|
13
8
|
|
14
|
-
delegate :config, :logger, to: :webpacker
|
9
|
+
delegate :config, :logger, :strategy, to: :webpacker
|
10
|
+
delegate :fresh?, :stale?, :after_compile_hook, to: :strategy
|
15
11
|
|
16
12
|
def initialize(webpacker)
|
17
13
|
@webpacker = webpacker
|
@@ -19,50 +15,18 @@ class Webpacker::Compiler
|
|
19
15
|
|
20
16
|
def compile
|
21
17
|
if stale?
|
22
|
-
run_webpack
|
18
|
+
run_webpack.tap do |success|
|
19
|
+
after_compile_hook
|
20
|
+
end
|
23
21
|
else
|
24
22
|
logger.debug "Everything's up-to-date. Nothing to do"
|
25
23
|
true
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
|
-
# Returns true if manifest file mtime is newer than the timestamp of the last modified watched file
|
30
|
-
def fresh?
|
31
|
-
manifest_mtime > latest_modified_timestamp
|
32
|
-
end
|
33
|
-
|
34
|
-
# Returns true if manifest file mtime is older than the timestamp of the last modified watched file
|
35
|
-
def stale?
|
36
|
-
!fresh?
|
37
|
-
end
|
38
|
-
|
39
27
|
private
|
40
28
|
attr_reader :webpacker
|
41
29
|
|
42
|
-
def manifest_mtime
|
43
|
-
config.manifest_path.exist? ? File.mtime(config.manifest_path).to_i : 0
|
44
|
-
end
|
45
|
-
|
46
|
-
def latest_modified_timestamp
|
47
|
-
if Rails.env.development?
|
48
|
-
warn <<~MSG.strip
|
49
|
-
Webpacker::Compiler - Slow setup for development
|
50
|
-
|
51
|
-
Prepare JS assets with either:
|
52
|
-
1. Running `bin/webpacker-dev-server`
|
53
|
-
2. Set `compile` to false in webpacker.yml and run `bin/webpacker -w`
|
54
|
-
MSG
|
55
|
-
end
|
56
|
-
|
57
|
-
warn "Webpacker::Compiler.watched_paths has been deprecated. Set additional_paths in webpacker.yml instead." unless watched_paths.empty?
|
58
|
-
root_path = Pathname.new(File.expand_path(config.root_path))
|
59
|
-
expanded_paths = [*default_watched_paths, *watched_paths].map do |path|
|
60
|
-
root_path.join(path)
|
61
|
-
end
|
62
|
-
latest_modified = Dir[*expanded_paths].max_by { |f| File.mtime(f) }
|
63
|
-
File.mtime(latest_modified).to_i
|
64
|
-
end
|
65
|
-
|
66
30
|
def optionalRubyRunner
|
67
31
|
bin_webpack_path = config.root_path.join("bin/webpacker")
|
68
32
|
first_line = File.readlines(bin_webpack_path).first.chomp
|
@@ -93,15 +57,6 @@ class Webpacker::Compiler
|
|
93
57
|
status.success?
|
94
58
|
end
|
95
59
|
|
96
|
-
def default_watched_paths
|
97
|
-
[
|
98
|
-
*config.additional_paths.map { |path| "#{path}{,/**/*}" },
|
99
|
-
"#{config.source_path}{,/**/*}",
|
100
|
-
"yarn.lock", "package.json",
|
101
|
-
"config/webpack{,/**/*}"
|
102
|
-
].freeze
|
103
|
-
end
|
104
|
-
|
105
60
|
def webpack_env
|
106
61
|
return env unless defined?(ActionController::Base)
|
107
62
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "webpacker/mtime_strategy"
|
2
|
+
require "webpacker/digest_strategy"
|
3
|
+
|
4
|
+
module Webpacker
|
5
|
+
class CompilerStrategy
|
6
|
+
def self.from_config
|
7
|
+
strategy_from_config = Webpacker.config.compiler_strategy
|
8
|
+
|
9
|
+
case strategy_from_config
|
10
|
+
when "mtime"
|
11
|
+
Webpacker::MtimeStrategy.new
|
12
|
+
when "digest"
|
13
|
+
Webpacker::DigestStrategy.new
|
14
|
+
else
|
15
|
+
raise "Unknown strategy '#{strategy_from_config}'. " \
|
16
|
+
"Available options are 'mtime' and 'digest'."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
require "webpacker/base_strategy"
|
3
|
+
|
4
|
+
module Webpacker
|
5
|
+
class DigestStrategy < BaseStrategy
|
6
|
+
# Returns true if all the compiled packs are up to date with the underlying asset files.
|
7
|
+
def fresh?
|
8
|
+
last_compilation_digest&.== watched_files_digest
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns true if the compiled packs are out of date with the underlying asset files.
|
12
|
+
def stale?
|
13
|
+
!fresh?
|
14
|
+
end
|
15
|
+
|
16
|
+
def after_compile_hook
|
17
|
+
# We used to only record the digest on success
|
18
|
+
# However, the output file is still written on error, meaning that the digest should still be updated.
|
19
|
+
# If it's not, you can end up in a situation where a recompile doesn't take place when it should.
|
20
|
+
# See https://github.com/rails/webpacker/issues/2113
|
21
|
+
record_compilation_digest
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def last_compilation_digest
|
27
|
+
compilation_digest_path.read if compilation_digest_path.exist? && config.manifest_path.exist?
|
28
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
29
|
+
end
|
30
|
+
|
31
|
+
def watched_files_digest
|
32
|
+
if Rails.env.development?
|
33
|
+
warn <<~MSG.strip
|
34
|
+
Webpacker::Compiler - Slow setup for development
|
35
|
+
Prepare JS assets with either:
|
36
|
+
1. Running `bin/webpacker-dev-server`
|
37
|
+
2. Set `compile` to false in webpacker.yml and run `bin/webpacker -w`
|
38
|
+
MSG
|
39
|
+
end
|
40
|
+
|
41
|
+
root_path = Pathname.new(File.expand_path(config.root_path))
|
42
|
+
expanded_paths = [*default_watched_paths].map do |path|
|
43
|
+
root_path.join(path)
|
44
|
+
end
|
45
|
+
files = Dir[*expanded_paths].reject { |f| File.directory?(f) }
|
46
|
+
file_ids = files.sort.map { |f| "#{File.basename(f)}/#{Digest::SHA1.file(f).hexdigest}" }
|
47
|
+
Digest::SHA1.hexdigest(file_ids.join("/"))
|
48
|
+
end
|
49
|
+
|
50
|
+
def record_compilation_digest
|
51
|
+
config.cache_path.mkpath
|
52
|
+
compilation_digest_path.write(watched_files_digest)
|
53
|
+
end
|
54
|
+
|
55
|
+
def compilation_digest_path
|
56
|
+
config.cache_path.join("last-compilation-digest-#{Webpacker.env}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/webpacker/instance.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "webpacker/base_strategy"
|
2
|
+
|
3
|
+
module Webpacker
|
4
|
+
class MtimeStrategy < BaseStrategy
|
5
|
+
# Returns true if manifest file mtime is newer than the timestamp of the last modified watched file
|
6
|
+
def fresh?
|
7
|
+
manifest_mtime > latest_modified_timestamp
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns true if manifest file mtime is older than the timestamp of the last modified watched file
|
11
|
+
def stale?
|
12
|
+
!fresh?
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def manifest_mtime
|
18
|
+
config.manifest_path.exist? ? File.mtime(config.manifest_path).to_i : 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def latest_modified_timestamp
|
22
|
+
if Rails.env.development?
|
23
|
+
warn <<~MSG.strip
|
24
|
+
Webpacker::Compiler - Slow setup for development
|
25
|
+
|
26
|
+
Prepare JS assets with either:
|
27
|
+
1. Running `bin/webpacker-dev-server`
|
28
|
+
2. Set `compile` to false in webpacker.yml and run `bin/webpacker -w`
|
29
|
+
MSG
|
30
|
+
end
|
31
|
+
|
32
|
+
root_path = Pathname.new(File.expand_path(config.root_path))
|
33
|
+
expanded_paths = [*default_watched_paths].map do |path|
|
34
|
+
root_path.join(path)
|
35
|
+
end
|
36
|
+
latest_modified = Dir[*expanded_paths].max_by { |f| File.mtime(f) }
|
37
|
+
File.mtime(latest_modified).to_i
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/webpacker/version.rb
CHANGED
data/package/rules/file.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
const { dirname
|
1
|
+
const { dirname } = require('path')
|
2
2
|
const { source_path: sourcePath } = require('../config')
|
3
3
|
|
4
4
|
module.exports = {
|
@@ -12,7 +12,7 @@ module.exports = {
|
|
12
12
|
.split('/')
|
13
13
|
.slice(1)
|
14
14
|
|
15
|
-
const foldersWithStatic =
|
15
|
+
const foldersWithStatic = ['static', ...folders].join('/')
|
16
16
|
return `${foldersWithStatic}/[name]-[hash][ext][query]`
|
17
17
|
}
|
18
18
|
}
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "shakapacker",
|
3
|
-
"version": "6.3.0
|
3
|
+
"version": "6.3.0",
|
4
4
|
"description": "Use webpack to manage app-like JavaScript modules in Rails",
|
5
5
|
"main": "package/index.js",
|
6
6
|
"files": [
|
@@ -13,7 +13,7 @@
|
|
13
13
|
},
|
14
14
|
"peerDependencies": {
|
15
15
|
"@babel/core": "^7.17.9",
|
16
|
-
"@babel/plugin-transform-runtime": "^7.17.
|
16
|
+
"@babel/plugin-transform-runtime": "^7.17.0",
|
17
17
|
"@babel/preset-env": "^7.16.11",
|
18
18
|
"@babel/runtime": "^7.17.9",
|
19
19
|
"babel-loader": "^8.2.4",
|
@@ -22,7 +22,7 @@
|
|
22
22
|
"webpack": "^5.72.0",
|
23
23
|
"webpack-assets-manifest": "^5.0.6",
|
24
24
|
"webpack-cli": "^4.9.2",
|
25
|
-
"webpack-dev-server": "^4.
|
25
|
+
"webpack-dev-server": "^4.9.0",
|
26
26
|
"webpack-merge": "^5.8.0"
|
27
27
|
},
|
28
28
|
"dependencies": {
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CompilerStrategyTest < Minitest::Test
|
4
|
+
def test_mtime_strategy_returned
|
5
|
+
Webpacker.config.stub :compiler_strategy, "mtime" do
|
6
|
+
assert_instance_of Webpacker::MtimeStrategy, Webpacker::CompilerStrategy.from_config
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_digest_strategy_returned
|
11
|
+
Webpacker.config.stub :compiler_strategy, "digest" do
|
12
|
+
assert_instance_of Webpacker::DigestStrategy, Webpacker::CompilerStrategy.from_config
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_raise_on_unknown_strategy
|
17
|
+
Webpacker.config.stub :compiler_strategy, "other" do
|
18
|
+
error = assert_raises do
|
19
|
+
Webpacker::CompilerStrategy.from_config
|
20
|
+
end
|
21
|
+
|
22
|
+
assert_equal \
|
23
|
+
"Unknown strategy 'other'. Available options are 'mtime' and 'digest'.",
|
24
|
+
error.message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/test/compiler_test.rb
CHANGED
@@ -9,46 +9,43 @@ class CompilerTest < Minitest::Test
|
|
9
9
|
Webpacker.compiler.env = {}
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
Webpacker.compiler.stub :latest_modified_timestamp, latest_timestamp do
|
18
|
-
FileTest.stub :exist?, manifest_exists do
|
19
|
-
File.stub :mtime, @manifest_timestamp do
|
20
|
-
yield
|
21
|
-
end
|
22
|
-
end
|
12
|
+
def test_compile_true_when_fresh
|
13
|
+
mock = Minitest::Mock.new
|
14
|
+
mock.expect(:stale?, false)
|
15
|
+
Webpacker.compiler.stub(:strategy, mock) do
|
16
|
+
assert Webpacker.compiler.compile
|
23
17
|
end
|
18
|
+
assert_mock mock
|
24
19
|
end
|
25
20
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
assert Webpacker.compiler.stale?
|
31
|
-
end
|
32
|
-
end
|
21
|
+
def test_after_compile_hook_called_on_success
|
22
|
+
mock = Minitest::Mock.new
|
23
|
+
mock.expect(:stale?, true)
|
24
|
+
mock.expect(:after_compile_hook, nil)
|
33
25
|
|
34
|
-
|
35
|
-
latest_timestamp = @manifest_timestamp + 3600
|
26
|
+
status = OpenStruct.new(success?: true)
|
36
27
|
|
37
|
-
|
38
|
-
|
28
|
+
Webpacker.compiler.stub(:strategy, mock) do
|
29
|
+
Open3.stub :capture3, [:sterr, :stdout, status] do
|
30
|
+
Webpacker.compiler.compile
|
31
|
+
end
|
39
32
|
end
|
33
|
+
assert_mock mock
|
40
34
|
end
|
41
35
|
|
42
|
-
def
|
43
|
-
|
36
|
+
def test_after_compile_hook_called_on_failure
|
37
|
+
mock = Minitest::Mock.new
|
38
|
+
mock.expect(:stale?, true)
|
39
|
+
mock.expect(:after_compile_hook, nil)
|
44
40
|
|
45
|
-
|
46
|
-
assert Webpacker.compiler.fresh?
|
47
|
-
end
|
48
|
-
end
|
41
|
+
status = OpenStruct.new(success?: false)
|
49
42
|
|
50
|
-
|
51
|
-
|
43
|
+
Webpacker.compiler.stub(:strategy, mock) do
|
44
|
+
Open3.stub :capture3, [:sterr, :stdout, status] do
|
45
|
+
Webpacker.compiler.compile
|
46
|
+
end
|
47
|
+
end
|
48
|
+
assert_mock mock
|
52
49
|
end
|
53
50
|
|
54
51
|
def test_external_env_variables
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class DigestStrategyTest < Minitest::Test
|
4
|
+
def remove_compilation_digest_path
|
5
|
+
@digest_strategy.send(:compilation_digest_path).tap do |path|
|
6
|
+
path.delete if path.exist?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@digest_strategy = Webpacker::DigestStrategy.new
|
12
|
+
remove_compilation_digest_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
remove_compilation_digest_path
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_freshness
|
20
|
+
assert @digest_strategy.stale?
|
21
|
+
assert !@digest_strategy.fresh?
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_freshness_after_compilation_hook
|
25
|
+
@digest_strategy.after_compile_hook
|
26
|
+
assert @digest_strategy.fresh?
|
27
|
+
assert !@digest_strategy.stale?
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_compilation_digest_path
|
31
|
+
assert_equal @digest_strategy.send(:compilation_digest_path).basename.to_s, "last-compilation-digest-#{Webpacker.env}"
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class MtimeStrategyTest < Minitest::Test
|
4
|
+
def setup
|
5
|
+
@mtime_strategy = Webpacker::MtimeStrategy.new
|
6
|
+
@manifest_timestamp = Time.parse("2021-01-01 12:34:56 UTC")
|
7
|
+
end
|
8
|
+
|
9
|
+
def with_stubs(latest_timestamp:, manifest_exists: true)
|
10
|
+
@mtime_strategy.stub :latest_modified_timestamp, latest_timestamp do
|
11
|
+
FileTest.stub :exist?, manifest_exists do
|
12
|
+
File.stub :mtime, @manifest_timestamp do
|
13
|
+
yield
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_freshness_when_manifest_missing
|
20
|
+
latest_timestamp = @manifest_timestamp + 3600
|
21
|
+
|
22
|
+
with_stubs(latest_timestamp: latest_timestamp.to_i, manifest_exists: false) do
|
23
|
+
assert @mtime_strategy.stale?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_freshness_when_manifest_older
|
28
|
+
latest_timestamp = @manifest_timestamp + 3600
|
29
|
+
|
30
|
+
with_stubs(latest_timestamp: latest_timestamp.to_i) do
|
31
|
+
assert @mtime_strategy.stale?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_freshness_when_manifest_newer
|
36
|
+
latest_timestamp = @manifest_timestamp - 3600
|
37
|
+
|
38
|
+
with_stubs(latest_timestamp: latest_timestamp.to_i) do
|
39
|
+
assert @mtime_strategy.fresh?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shakapacker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.3.0
|
4
|
+
version: 6.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-
|
13
|
+
date: 2022-05-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- docs/customizing_babel_config.md
|
143
143
|
- docs/deployment.md
|
144
144
|
- docs/developing_webpacker.md
|
145
|
+
- docs/react.md
|
145
146
|
- docs/style_loader_vs_mini_css.md
|
146
147
|
- docs/troubleshooting.md
|
147
148
|
- docs/using_esbuild_loader.md
|
@@ -179,16 +180,20 @@ files:
|
|
179
180
|
- lib/tasks/webpacker/yarn_install.rake
|
180
181
|
- lib/tasks/yarn.rake
|
181
182
|
- lib/webpacker.rb
|
183
|
+
- lib/webpacker/base_strategy.rb
|
182
184
|
- lib/webpacker/commands.rb
|
183
185
|
- lib/webpacker/compiler.rb
|
186
|
+
- lib/webpacker/compiler_strategy.rb
|
184
187
|
- lib/webpacker/configuration.rb
|
185
188
|
- lib/webpacker/dev_server.rb
|
186
189
|
- lib/webpacker/dev_server_proxy.rb
|
187
190
|
- lib/webpacker/dev_server_runner.rb
|
191
|
+
- lib/webpacker/digest_strategy.rb
|
188
192
|
- lib/webpacker/env.rb
|
189
193
|
- lib/webpacker/helper.rb
|
190
194
|
- lib/webpacker/instance.rb
|
191
195
|
- lib/webpacker/manifest.rb
|
196
|
+
- lib/webpacker/mtime_strategy.rb
|
192
197
|
- lib/webpacker/railtie.rb
|
193
198
|
- lib/webpacker/runner.rb
|
194
199
|
- lib/webpacker/version.rb
|
@@ -236,10 +241,12 @@ files:
|
|
236
241
|
- package/utils/helpers.js
|
237
242
|
- rakelib/release.rake
|
238
243
|
- test/command_test.rb
|
244
|
+
- test/compiler_strategy_test.rb
|
239
245
|
- test/compiler_test.rb
|
240
246
|
- test/configuration_test.rb
|
241
247
|
- test/dev_server_runner_test.rb
|
242
248
|
- test/dev_server_test.rb
|
249
|
+
- test/digest_strategy_test.rb
|
243
250
|
- test/engine_rake_tasks_test.rb
|
244
251
|
- test/env_test.rb
|
245
252
|
- test/fixtures/beta_package.json
|
@@ -261,6 +268,7 @@ files:
|
|
261
268
|
- test/mounted_app/test/dummy/config/environment.rb
|
262
269
|
- test/mounted_app/test/dummy/config/webpacker.yml
|
263
270
|
- test/mounted_app/test/dummy/package.json
|
271
|
+
- test/mtime_strategy_test.rb
|
264
272
|
- test/rake_tasks_test.rb
|
265
273
|
- test/test_app/Rakefile
|
266
274
|
- test/test_app/app/packs/entrypoints/application.js
|
@@ -292,7 +300,7 @@ homepage: https://github.com/shakacode/shakapacker
|
|
292
300
|
licenses:
|
293
301
|
- MIT
|
294
302
|
metadata:
|
295
|
-
source_code_uri: https://github.com/shakacode/shakapacker/tree/v6.3.0
|
303
|
+
source_code_uri: https://github.com/shakacode/shakapacker/tree/v6.3.0
|
296
304
|
post_install_message:
|
297
305
|
rdoc_options: []
|
298
306
|
require_paths:
|
@@ -304,9 +312,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
304
312
|
version: 2.6.0
|
305
313
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
306
314
|
requirements:
|
307
|
-
- - "
|
315
|
+
- - ">="
|
308
316
|
- !ruby/object:Gem::Version
|
309
|
-
version:
|
317
|
+
version: '0'
|
310
318
|
requirements: []
|
311
319
|
rubygems_version: 3.2.32
|
312
320
|
signing_key:
|
@@ -314,10 +322,12 @@ specification_version: 4
|
|
314
322
|
summary: Use webpack to manage app-like JavaScript modules in Rails
|
315
323
|
test_files:
|
316
324
|
- test/command_test.rb
|
325
|
+
- test/compiler_strategy_test.rb
|
317
326
|
- test/compiler_test.rb
|
318
327
|
- test/configuration_test.rb
|
319
328
|
- test/dev_server_runner_test.rb
|
320
329
|
- test/dev_server_test.rb
|
330
|
+
- test/digest_strategy_test.rb
|
321
331
|
- test/engine_rake_tasks_test.rb
|
322
332
|
- test/env_test.rb
|
323
333
|
- test/fixtures/beta_package.json
|
@@ -339,6 +349,7 @@ test_files:
|
|
339
349
|
- test/mounted_app/test/dummy/config/environment.rb
|
340
350
|
- test/mounted_app/test/dummy/config/webpacker.yml
|
341
351
|
- test/mounted_app/test/dummy/package.json
|
352
|
+
- test/mtime_strategy_test.rb
|
342
353
|
- test/rake_tasks_test.rb
|
343
354
|
- test/test_app/Rakefile
|
344
355
|
- test/test_app/app/packs/entrypoints/application.js
|