A wepback loader using comment to do precompilation work.
###Install
npm install --save-dev comment-loader
###Why we need it?
Conditional code is not allowed in ES6+, this means you cannot use if-else
or switch-case
structure to enable/disable some modules.
However if some precompilation work can be performed before webpack pass your code to babel or other ES transformers, the problem can be solved easily.
Macro like C-style macro can be a way to do all this.
###What different? Some Macro loaders can already be found on github or npm. However, they usually cause some side-effects. Using Macro directly will break the syntax which will cause big problem if the loader is not available.
Here I use the hack on comments and babylon
parser to detect the define Macro. Using comments is a way to lower the side-effects as many as possible, though it still bother IDE sometimes.
Comments are not force to be at the beginning of the line, since babylon
can always detect AST correctly. Another important reason why I use babylon
is that I hope the comments can do more in future. Maybe I'll let loader support simple if-else
or switch-case
structures in comments with some defined patterns.
###When to use it? Here is an example of developing app with redux.
import {createStore, compose} from 'redux';
import rootReducer from '../reducers';
import {persistState} from 'redux-devtools';
import DevTools from '../containers/DevTools';
const enhancer = compose(
DevTools.instrument(),
persistState(
window.location.href.match(
/[?&]debug_session=([^&#]+)\b/
)
)
);
export default function configureStore(initialState) {
return createStore(rootReducer, initialState, process.env.NODE_ENV === 'production' ? undefined : enhancer);
}
redux-devtools
is very useful when developing apps, however it only use WebpackDefine
plugin can have great problem when build bundles.WebpackDefine
works after babel-loader
but before uglify
which means the modules are already bundled together before the WebpackDefine
plugin works.
This problem in this issue is almost the same. The tree shaking won't work because building modules is performed before removing dead code. Webpack can mark unused imports/exports, maybe this is also possible for the issue by some ways like simply marking the statements and specifiers. But in my case, I think it is impossible. If an analyzer can tell enhancer
is no longer used when process.env.NODE_ENV === 'production'
, and it cannot tell whether compose
use it or not.
If recursive detection can be performed, it must be a time consuming work.
I now think these kind of use WebpackDefine
plugin is a mistake, especially when the variables defined are related to the module dependency. So I don't think Webpack
should focus on this kind of problem.
This loader allows you to write code like below:
import {createStore, compose} from 'redux';
import rootReducer from '../reducers';
//<#IF_DEF DEBUG>
import {persistState} from 'redux-devtools';
import DevTools from '../containers/DevTools';
const enhancer = compose(
DevTools.instrument(),
persistState(
window.location.href.match(
/[?&]debug_session=([^&#]+)\b/
)
)
);
//<#END_IF>
export default function configureStore(initialState) {
let store;
//<#IF_DEF DEBUG>
store = createStore(rootReducer, initialState, enhancer);
//<#ELSE>
store = createStore(rootReducer, initialState);
//<#END_IF>
return store;
}
The <#IF_DEF DEBUG>
, <#ELSE>
and <#END_IF>
are all needed.
###How to use? Webpack config file.
module: {
rules: [
{
test: /\.js$/,
include: [
path.resolve(__dirname, '../src')
],
exclude: [
path.resolve(__dirname, '../node_modules')
],
use: [
{
loader: 'babel-loader'
},
{
loader: 'comment-loader',
options: {
definition: ['DEBUG']//['RELEASE']
}
},
]
}
]
}
Note: You should always put
comment-loader
on the right ofbabel-loader
or other loaders.babel-loader
will mess up the comments betweenimport
lines thus making macros invalid.