Hello !
On a project, we want to be able to remove code from a bundle using environment variables.
As it was not working as expected I made a simple reproduction with the default gatsby starter:
https://github.com/abumalick/gatsby-dead-code-removing
Here are the steps that I followed:
in pages/index.js:
import React from 'react'
import { Link } from 'gatsby'
import Layout from '../components/layout'
const IndexPage = () => {
+ if (process.env.GATSBY_SHOULD_BE_REMOVED){
+ console.log('THIS IS NOT REMOVED AND SHOULD BE')
+ }
+ if (!process.env.GATSBY_SHOULD_BE_REMOVED){
+ console.log('THIS SHOULD NOT BE REMOVED');
+ }
+ if (false) {
+ console.log('THIS IS CORRECTLY REMOVED')
+ }
return (
<Layout>
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)
}
export default IndexPage
After this I run npm run build (I didn't set any env variable).
in component---src-pages-index-js-....js:
Object({
NODE_ENV: 'production',
PUBLIC_DIR:
'/Users/abumalick/Documents/workspace/gatsby-dead-code-removing/public',
BUILD_STAGE: 'build-javascript',
GATSBY_BUILD_STAGE: 'build-javascript',
}).GATSBY_SHOULD_BE_REMOVED &&
console.log('THIS IS NOT REMOVED AND SHOULD BE'),
Object({
NODE_ENV: 'production',
PUBLIC_DIR:
'/Users/abumalick/Documents/workspace/gatsby-dead-code-removing/public',
BUILD_STAGE: 'build-javascript',
GATSBY_BUILD_STAGE: 'build-javascript',
}).GATSBY_SHOULD_BE_REMOVED ||
console.log('THIS SHOULD NOT BE REMOVED'),
I was excepting that the code would be totally removed from the final bundle.
Is this the normal behavior ?
Is it possible to change this ?
I was testing this on our app in gatsby v1 because we have a use case for using this. When I noticed that it didn't work as I expected, I tried with gatsby v2 and here is the result.
I am interested to fix this on gatsby v1 as well, as it will take some time to migrate our app (we hacked react-router a lot).
System:
OS: macOS High Sierra 10.13.6
CPU: x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
Shell: 5.3 - /bin/zsh
Binaries:
Node: 8.11.3 - ~/.nvm/versions/node/v8.11.3/bin/node
Yarn: 1.7.0 - /usr/local/bin/yarn
npm: 5.6.0 - ~/.nvm/versions/node/v8.11.3/bin/npm
Browsers:
Chrome: 69.0.3497.100
Firefox: 61.0.2
Safari: 12.0
npmPackages:
gatsby: ^2.0.0 => 2.0.7
gatsby-plugin-manifest: ^2.0.2 => 2.0.2
gatsby-plugin-offline: ^2.0.5 => 2.0.5
gatsby-plugin-react-helmet: ^3.0.0 => 3.0.0
gatsby-config.js: N/A
package.json: N/A
gatsby-node.js: N/A
gatsby-browser.js: N/A
gatsby-ssr.js: N/A
Hi @abumalick, this is a great idea. We can do this by using babel-plugin-transform-inline-environment-variables. Would you like to work on this and create a Gatsby plugin for this?
ok, I start working on this.
Thank you for the tip, it worked for me with a simple change in gatsby-node.js
exports.onCreateBabelConfig = ({ actions }, pluginOptions) => {
actions.setBabelPlugin({
name: `babel-plugin-transform-inline-environment-variables`,
})
}
Now I am trying to find a way to remove unused import files, so we could write our code like the following and get the unused imports totally removed.
import React from 'react'
import { Link } from 'gatsby'
+ import TestComponent from '../components/TestComponent'
import Layout from '../components/layout'
const IndexPage = () => {
if (process.env.GATSBY_SHOULD_BE_REMOVED){
console.log('THIS IS NOT REMOVED AND SHOULD BE')
}
if (!process.env.GATSBY_SHOULD_BE_REMOVED){
console.log('THIS SHOULD NOT BE REMOVED');
}
if (false) {
console.log('THIS IS CORRECTLY REMOVED')
}
return (
<Layout>
<h1>Hi people</h1>
+ {process.env.GATSBY_SHOULD_BE_REMOVED && <TestComponent />}
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)
}
export default IndexPage
I didn't find a solution yet. I think that loading it async would be the simplest but we lose some performance.
Thanks again.
interesting! 👍
@abumalick maybe this one can help ember-cli/babel-plugin-filter-imports?
Or maybe this dangerous one imcuttle/babel-plugin-danger-remove-unused-import
Please let me know if you get it working, could be useful to know 💯
Thanks @CanRau , the second plugins seemed to be what I was looking for. I tried it but it does not work for my case.
I think that the line {process.env.GATSBY_SHOULD_BE_REMOVED && <TestComponent />} is removed by uglifyjs, so playing with babel to remove TestComponent import will not work (it is too early).
I wonder if uglifyjs can remove that component that is not used, any idea how we can modify uglifyjs implementation ?
Right now I am a bit stuck and am planning to load the components async, so I am sure it is removed from normal bundle.
Hmmm, I feel like this should be builtin in Gatsby. We also use process.env vars in runtime - so need to investigate if gatsby runtime has same problem
@abumalick Have no further ideas right now sorry, would have to dig deeper and don't have the need/curiosity right now ;)
but when available I might use it myself
the first one does not work? filtering the imports…probably to much manual config needed
maybe a custom babel plugin wouldn't be too hard, haven't had the chance to get into this yet though…
looking forward to @pieh's input 👍
Old issues will be closed after 30 days of inactivity. This issue has been quiet for 20 days and is being marked as stale. Reply here or add the label "not stale" to keep this issue open!
This issue is being closed due to inactivity. Is this a mistake? Please re-open this issue or create a new issue.
@abumalick Maybe babel-plugin-preval could help if you still need a solution?
The imported module should (not tested so not sure) be able to export your desired component if the flag is set or null otherwise which would render nothing in react.. 🤔
mmh, it is a very good idea, thank you very much @CanRau
Right now we are using a babel plugin so that env variables correctly remove the code:
exports.onCreateBabelConfig = ({actions}) => {
actions.setBabelPlugin({
// With this plugin, you need to remove "node_modules/.cache" when you change environment variables !
name: `babel-plugin-transform-inline-environment-variables`,
});
};
And for the dead code that result from the import, we are simply loading the component that could be removed asynchronously:
import reactAsync from 'core/libs/hoc/reactAsync';
const AsyncCourseAdmin =
process.env.ADMIN_MODE &&
reactAsync({
loader: () => import('./CourseAdmin'),
loading: null,
});
export default AsyncCourseAdmin;
export default ({loader, loading}) =>
class ReactAsync extends Component {
state = {};
componentDidMount() {
loader()
.then((c) => {
this.setState({Child: c.default});
})
.catch((e) => {
console.error('Could not load react component', e);
});
}
render() {
const {Child} = this.state;
if (Child) {
return <Child {...this.props} />;
}
return loading;
}
};
It correctly remove the admin components from normal build.
But I think preval would be a very good idea in this situation, thank you very much for sharing that !
Awesome glad it's working as desired 🥳
It's a pleasure 😃
Most helpful comment
Hmmm, I feel like this should be builtin in Gatsby. We also use process.env vars in runtime - so need to investigate if gatsby runtime has same problem