Skip to content

Commit 00a570e

Browse files
alexeyr-cialexeyr
andauthored
Detect dead code and unused dependencies (#1687)
* Use Knip to detect dead code * Remove unused dependencies * Move some dummy dependencies to devDependencies * Improve types for Node Package --------- Co-authored-by: Alexey Romanov <alexey.v.romanov@gmail.com>
1 parent 34dae0d commit 00a570e

File tree

18 files changed

+454
-2224
lines changed

18 files changed

+454
-2224
lines changed

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ node_package/webpack.config.js
1515
**/public/packs*/*
1616
gen-examples
1717
bundle/
18+
# Can't get it working in CI
19+
knip.ts

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extends:
44
- prettier/react
55

66
plugins:
7+
- import
78
- prettier
89

910
globals:

.github/workflows/lint-js-and-ruby.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,19 @@ jobs:
4747
yarn install --no-progress --no-emoji
4848
- name: Install Ruby Gems for package
4949
run: bundle check --path=vendor/bundle || bundle _2.5.9_ install --path=vendor/bundle --jobs=4 --retry=3
50-
- name: Linting of Ruby
50+
- name: Lint Ruby
5151
run: bundle exec rubocop
52-
- name: Linting of JS
52+
- name: Install Node modules with Yarn for dummy app
53+
run: cd spec/dummy && yarn install --ignore-scripts --no-progress --no-emoji
54+
- name: Install Ruby Gems for dummy app
55+
run: cd spec/dummy && bundle lock --add-platform 'x86_64-linux' && bundle check --path=vendor/bundle || bundle _2.5.9_ install --path=vendor/bundle --jobs=4 --retry=3
56+
- name: generate file system-based packs
57+
run: cd spec/dummy && RAILS_ENV=test bundle exec rake react_on_rails:generate_packs
58+
- name: Detect dead code
59+
run: |
60+
yarn run knip
61+
yarn run knip --production
62+
- name: Lint JS
5363
run: yarn start lint
5464
- name: Check formatting
5565
run: yarn start format.listDifferent

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
- name: generate file system-based packs
7272
run: cd spec/dummy && RAILS_ENV=test bundle exec rake react_on_rails:generate_packs
7373
- name: Build test bundles for dummy app
74-
run: cd spec/dummy && rm -rf public/webpack/test && yarn build:rescript && RAILS_ENV=test NODE_ENV=test bin/${{ matrix.versions == 'oldest' && 'web' || 'shaka' }}packer
74+
run: cd spec/dummy && rm -rf public/webpack/test && yarn run build:rescript && RAILS_ENV=test NODE_ENV=test bin/${{ matrix.versions == 'oldest' && 'web' || 'shaka' }}packer
7575
- id: get-sha
7676
run: echo "::set-output name=sha::$(git rev-parse HEAD)"
7777
- name: Save test webpack bundles to cache (for build number checksum used by rspec job)

.github/workflows/package-js-tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ jobs:
3333
with:
3434
path: node_modules
3535
key: v5-package-node-modules-cache-${{ hashFiles('yarn.lock') }}
36+
- name: run conversion script
37+
if: matrix.versions == 'oldest'
38+
run: script/convert
3639
- name: Install Node modules with Yarn for renderer package
3740
run: |
3841
yarn install --no-progress --no-emoji

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
react_on_rails (14.1.0)
4+
react_on_rails (14.1.1)
55
addressable
66
connection_pool
77
execjs (~> 2.5)

knip.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import type { KnipConfig } from 'knip';
2+
3+
const config: KnipConfig = {
4+
// ! at the end means files are used in production
5+
workspaces: {
6+
'.': {
7+
entry: ['node_package/src/ReactOnRails.ts!', 'node_package/src/ReactOnRails.node.ts!'],
8+
project: ['node_package/src/**/*.[jt]s!', 'node_package/tests/**/*.[jt]s'],
9+
babel: {
10+
config: ['node_package/babel.config.js'],
11+
},
12+
ignoreBinaries: [
13+
// Knip fails to detect it's declared in devDependencies
14+
'nps',
15+
// local scripts
16+
'node_package/scripts/.*',
17+
],
18+
ignoreDependencies: [
19+
// Required for TypeScript compilation, but we don't depend on Turbolinks itself.
20+
'@types/turbolinks',
21+
// used in package-scripts.yml
22+
'concurrently',
23+
// The Knip ESLint plugin fails to detect these are transitively required by a config,
24+
// though we don't actually use its rules anywhere.
25+
'eslint-plugin-jsx-a11y',
26+
'eslint-plugin-react',
27+
],
28+
},
29+
'spec/dummy': {
30+
entry: [
31+
'app/assets/config/manifest.js!',
32+
'client/app/packs/**/*.js!',
33+
// Not sure why this isn't detected as a dependency of client/app/packs/server-bundle.js
34+
'client/app/generated/server-bundle-generated.js!',
35+
'spec/fixtures/automated_packs_generation/**/*.js{x,}',
36+
'config/webpack/{production,development,test}.js',
37+
// Declaring this as webpack.config instead doesn't work correctly
38+
'config/webpack/webpack.config.js',
39+
],
40+
project: ['**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}!', 'config/webpack/*.js'],
41+
paths: {
42+
'Assets/*': ['client/app/assets/*'],
43+
},
44+
ignoreBinaries: [
45+
// Has to be installed globally
46+
'yalc',
47+
// Local binaries
48+
'bin/.*',
49+
],
50+
ignoreDependencies: [
51+
// Knip thinks it can be a devDependency, but it's supposed to be in dependencies.
52+
'@babel/runtime',
53+
// There's no ReScript plugin for Knip
54+
'@rescript/react',
55+
// The Babel plugin fails to detect it
56+
'babel-plugin-transform-react-remove-prop-types',
57+
// This one is weird. It's long-deprecated and shouldn't be necessary.
58+
// Probably need to update the Webpack config.
59+
'node-libs-browser',
60+
// The below dependencies are not detected by the Webpack plugin
61+
// due to the config issue.
62+
'css-loader',
63+
'expose-loader',
64+
'file-loader',
65+
'imports-loader',
66+
'mini-css-extract-plugin',
67+
'null-loader',
68+
'sass',
69+
'sass-loader',
70+
'sass-resources-loader',
71+
'style-loader',
72+
'url-loader',
73+
],
74+
},
75+
},
76+
};
77+
78+
export default config;

node_package/src/buildConsoleReplay.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ declare global {
99
}
1010
}
1111

12+
/** @internal Exported only for tests */
1213
export function consoleReplay(customConsoleHistory: typeof console['history'] | undefined = undefined, numberOfMessagesToSkip: number = 0): string {
1314
// console.history is a global polyfill used in server rendering.
1415
const consoleHistory = customConsoleHistory ?? console.history;

node_package/src/clientStartup.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
RenderFunction,
88
Root,
99
} from './types';
10+
import type { Context } from './context';
1011

1112
import createReactOutput from './createReactOutput';
1213
import { isServerRenderHash } from './isServerRenderResult';
@@ -22,12 +23,13 @@ declare global {
2223
roots: Root[];
2324
}
2425

25-
namespace NodeJS {
26-
interface Global {
27-
ReactOnRails: ReactOnRailsType;
28-
roots: Root[];
29-
}
26+
namespace globalThis {
27+
/* eslint-disable no-var,vars-on-top */
28+
var ReactOnRails: ReactOnRailsType;
29+
var roots: Root[];
30+
/* eslint-enable no-var,vars-on-top */
3031
}
32+
3133
namespace Turbolinks {
3234
interface TurbolinksStatic {
3335
controller?: unknown;
@@ -39,8 +41,6 @@ declare const ReactOnRails: ReactOnRailsType;
3941

4042
const REACT_ON_RAILS_STORE_ATTRIBUTE = 'data-js-react-on-rails-store';
4143

42-
type Context = Window | NodeJS.Global;
43-
4444
function findContext(): Context {
4545
if (typeof window.ReactOnRails !== 'undefined') {
4646
return window;

node_package/src/context.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
export type Context = Window | typeof globalThis;
2+
13
/**
24
* Get the context, be it window or global
3-
* @returns {boolean|Window|*|context}
45
*/
5-
export default function context(this: void): Window | NodeJS.Global | void {
6+
export default function context(this: void): Context | void {
67
return ((typeof window !== 'undefined') && window) ||
78
((typeof global !== 'undefined') && global) ||
89
this;

0 commit comments

Comments
 (0)