javascript - plugin - webpack html loader
Construcción condicional basada en el entorno usando Webpack (9)
Tengo algunas cosas para el desarrollo, por ejemplo, simulacros con los que me gustaría no llenar mi archivo de compilación distribuido.
En RequireJS, puede pasar una configuración en un archivo de complemento y, de forma condicional, requerir cosas basadas en eso.
Para webpack no parece haber una forma de hacerlo. En primer lugar, para crear una configuración de tiempo de ejecución para un entorno, he utilizado resolve.alias para resolve.alias un requerimiento dependiendo del entorno, por ejemplo:
// All settings.
var all = {
fish: ''salmon''
};
// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require(''envsettings''));
Luego, al crear la configuración del paquete web, puedo asignar dinámicamente a qué puntos de
envsettings
archivos apunta (ej.
webpackConfig.resolve.alias.envsettings = ''./'' + env
).
Sin embargo, me gustaría hacer algo como:
if (settings.mock) {
// Short-circuit ajax calls.
// Require in all the mock modules.
}
Pero obviamente no quiero construir esos archivos simulados si el entorno no es falso.
Posiblemente podría reenviar manualmente todos esos requisitos a un archivo stub usando resolve.alias nuevamente, pero ¿hay alguna manera que se sienta menos hacky?
¿Alguna idea de cómo puedo hacer eso? Gracias.
Enfrentado con el mismo problema que el OP y requerido, debido a la licencia, para no incluir cierto código en ciertas compilaciones, adopté el webpack-conditional-loader siguiente manera:
En mi comando de compilación establezco una variable de entorno adecuada para mi compilación. Por ejemplo ''demo'' en package.json:
...
"scripts": {
...
"buildDemo": "./node_modules/.bin/webpack --config webpack.config/demo.js --env.demo --progress --colors",
...
La parte confusa que falta en la documentación que leí es que tengo que hacer esto visible durante todo el proceso de compilación asegurándome de que mi variable env se inyecte en el proceso global, por lo tanto, en mi webpack.config / demo.js:
/* The demo includes project/reports action to access placeholder graphs.
This is achieved by using the webpack-conditional-loader process.env.demo === true
*/
const config = require(''./production.js'');
config.optimization = {...(config.optimization || {}), minimize: false};
module.exports = env => {
process.env = {...(process.env || {}), ...env};
return config};
Con esto en su lugar, puedo excluir condicionalmente cualquier cosa, asegurando que cualquier código relacionado se elimine correctamente del JavaScript resultante. Por ejemplo, en my routes.js, el contenido de demostración se mantiene fuera de otras compilaciones, por lo tanto:
...
// #if process.env.demo
import Reports from ''components/model/project/reports'';
// #endif
...
const routeMap = [
...
// #if process.env.demo
{path: "/project/reports/:id", component: Reports},
// #endif
...
Esto funciona con webpack 4.29.6.
He tenido problemas para configurar env en mis configuraciones de webpack.
Lo que generalmente quiero es configurar env para que pueda alcanzarse dentro de
webpack.config.js
,
postcss.config.js
y dentro de la aplicación de punto de entrada (
index.js
generalmente).
Espero que mis hallazgos puedan ayudar a alguien.
La solución que se me ocurrió es pasar
--env production
o
--env development
, y luego configurar el modo dentro de
webpack.config.js
.
Sin embargo, eso no me ayuda a hacer que
env
accesible donde lo quiero (ver arriba), por lo que también necesito configurar
process.env.NODE_ENV
explícitamente, como se recomienda
here
.
La parte más relevante que tengo en
webpack.config.js
sigue a continuación.
...
module.exports = mode => {
process.env.NODE_ENV = mode;
if (mode === "production") {
return merge(commonConfig, productionConfig, { mode });
}
return merge(commonConfig, developmentConfig, { mode });
};
No estoy seguro de por qué la respuesta "webpack.DefinePlugin" es la mejor en todas partes para definir las importaciones / requisitos basados en el entorno.
El problema con ese enfoque es que todavía está entregando todos esos módulos al cliente -> verifique con webpack-bundle-analyezer por ejemplo. Y no reduce el tamaño de tu bundle.js en absoluto :)
Entonces, lo que realmente funciona bien y es mucho más lógico es: NormalModuleReplacementPlugin
Entonces, en lugar de hacer un requerimiento condicional on_client -> simplemente no incluye los archivos no necesarios al paquete en primer lugar
Espero que ayude
Otra forma es usar un archivo JS como
proxy
y dejar que ese archivo cargue el módulo de interés en
commonjs
y exportarlo como
es2015 module
, de esta manera:
// file: myModule.dev.js
module.exports = "this is in dev"
// file: myModule.prod.js
module.exports = "this is in prod"
// file: myModule.js
let loadedModule
if(WEBPACK_IS_DEVELOPMENT){
loadedModule = require(''./myModule.dev.js'')
}else{
loadedModule = require(''./myModule.prod.js'')
}
export const myString = loadedModule
Entonces puede usar el módulo ES2015 en su aplicación normalmente:
// myApp.js
import { myString } from ''./store/myModule.js''
myString // <- "this is in dev"
Puede usar el complemento define .
Lo uso haciendo algo tan simple como esto en su archivo de compilación de paquete web donde
env
es la ruta a un archivo que exporta un objeto de configuración:
// Webpack build config
plugins: [
new webpack.DefinePlugin({
ENV: require(path.join(__dirname, ''./path-to-env-files/'', env))
})
]
// Settings file located at `path-to-env-files/dev.js`
module.exports = { debug: true };
y luego esto en tu código
if (ENV.debug) {
console.log(''Yo!'');
}
Eliminará este código de su archivo de compilación si la condición es falsa. Puede ver un ejemplo de compilación de Webpack funcional aquí .
Si bien esta no es la mejor solución, puede funcionar para algunas de sus necesidades. Si desea ejecutar un código diferente en el nodo y el navegador, esto funcionó para mí:
if (typeof window !== ''undefined'')
return
}
//run node only code now
Terminé usando algo similar a la respuesta de Matt Derrick , pero estaba preocupado por dos puntos:
-
La configuración completa se inyecta cada vez que uso
ENV
(que es malo para configuraciones grandes). -
Tengo que definir múltiples puntos de entrada porque
require(env)
puntosrequire(env)
a diferentes archivos.
Lo que se me ocurrió es un compositor simple que construye un objeto de configuración y lo inyecta en un módulo de configuración.
Aquí está la estructura de archivos, que estoy usando para esto:
config/
└── main.js
└── dev.js
└── production.js
src/
└── app.js
└── config.js
└── ...
webpack.config.js
main.js
contiene todas las cosas de configuración predeterminadas:
// main.js
const mainConfig = {
apiEndPoint: ''https://api.example.com'',
...
}
module.exports = mainConfig;
dev.js
y
production.js
solo contienen material de configuración que anula la configuración principal:
// dev.js
const devConfig = {
apiEndPoint: ''http://localhost:4000''
}
module.exports = devConfig;
La parte importante es el
webpack.config.js
que compone la configuración y usa
DefinePlugin
para generar una variable de entorno
__APP_CONFIG__
que contiene el objeto de configuración compuesto:
const argv = require(''yargs'').argv;
const _ = require(''lodash'');
const webpack = require(''webpack'');
// Import all app configs
const appConfig = require(''./config/main'');
const appConfigDev = require(''./config/dev'');
const appConfigProduction = require(''./config/production'');
const ENV = argv.env || ''dev'';
function composeConfig(env) {
if (env === ''dev'') {
return _.merge({}, appConfig, appConfigDev);
}
if (env === ''production'') {
return _.merge({}, appConfig, appConfigProduction);
}
}
// Webpack config object
module.exports = {
entry: ''./src/app.js'',
...
plugins: [
new webpack.DefinePlugin({
__APP_CONFIG__: JSON.stringify(composeConfig(ENV))
})
]
};
El último paso ahora es
config.js
, se ve así (Usando la sintaxis de exportación de importación es6 aquí porque está debajo del paquete web):
const config = __APP_CONFIG__;
export default config;
En su
app.js
ahora puede usar
import config from ''./config'';
para obtener el objeto de configuración.
Use github.com/nippur72/ifdef-loader . En tus archivos fuente puedes hacer cosas como
/// #if ENV === ''production''
console.log(''production!'');
/// #endif
La configuración del
webpack
relevante es
const preprocessor = {
ENV: process.env.NODE_ENV || ''development'',
};
const ifdef_query = require(''querystring'').encode({ json: JSON.stringify(preprocessor) });
const config = {
// ...
module: {
rules: [
// ...
{
test: //.js$/,
exclude: /node_modules/,
use: {
loader: `ifdef-loader?${ifdef_query}`,
},
},
],
},
// ...
};
Use variables de entorno para crear implementaciones de desarrollo y producción: