{"id":13432967,"url":"https://github.com/petehunt/webpack-howto","last_synced_at":"2025-05-14T06:13:35.007Z","repository":{"id":18720740,"uuid":"21931810","full_name":"petehunt/webpack-howto","owner":"petehunt","description":null,"archived":false,"fork":false,"pushed_at":"2017-08-11T02:36:03.000Z","size":469,"stargazers_count":10087,"open_issues_count":52,"forks_count":690,"subscribers_count":263,"default_branch":"master","last_synced_at":"2025-04-11T00:51:21.409Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/petehunt.png","metadata":{"files":{"readme":"README-es.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-07-17T06:55:48.000Z","updated_at":"2025-04-08T16:11:39.000Z","dependencies_parsed_at":"2022-07-26T23:46:03.090Z","dependency_job_id":null,"html_url":"https://github.com/petehunt/webpack-howto","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petehunt%2Fwebpack-howto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petehunt%2Fwebpack-howto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petehunt%2Fwebpack-howto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petehunt%2Fwebpack-howto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/petehunt","download_url":"https://codeload.github.com/petehunt/webpack-howto/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254083200,"owners_count":22011826,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T02:01:19.138Z","updated_at":"2025-05-14T06:13:34.981Z","avatar_url":"https://github.com/petehunt.png","language":"JavaScript","funding_links":[],"categories":["Awesome React","JavaScript","📦 Legacy \u0026 Inactive Projects","Front-End Development"],"sub_categories":["Resources"],"readme":"# webpack-howto\n\n## Objetivo de esta guía\n\nEsta es una guía sobre como lograr lo que uno quiere usando webpack. Incluye la mayoría de las cosas que utilizamos en Instagram y nada que no utilicemos.\n\nMi consejo: empezar con esta guía como tu documentación sobre webpack, y luego mirar la documentación oficial para aclarar conceptos y/o detalles.\n\n## Pre-Requisitos\n\n  * Saber sobre browserify, RequireJS o similares\n  * Ver valor en:\n    * Partir/fraccionar paquetes (Bundle splitting)\n    * Carga asincrónica (Async loading)\n    * Empaquetar contenido estático como imágenes y CSS\n\n## 1. Por que webpack?\n\n\n  * **Es como browserify** pero puede fraccionar nuestra app en múltiples archivos. Si tenemos múltiples paginas en una SPA (Single Page App), el usuario solo descarga el contenido correspondiente a la pagina actual. Si luego visita otra pagina, no vuelve a descargar código en común o repetido.\n\n  * **Generalmente reemplaza a grunt o gulp** porque puede construir y empaquetar CSS, CSS pre-procesado, lenguajes compilables-a-JS e imágenes, entre otras cosas.\n\nSoporta AMA, CommonJS y otros sistemas de módulos (Angular, ES6). Si no sabes que usar, usa CommonJS.\n\n## 2. Webpack para gente que usa Browserify\n\nEstos son equivalentes:\n\n```js\nbrowserify main.js \u003e bundle.js\n```\n\n```js\nwebpack main.js bundle.js\n```\n\nSin embargo, webpack es mas poderoso que Browserify, por lo que generalmente queremos crear el archivo `webpack.config.js` para organizarnos mejor:\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: './main.js',\n  output: {\n    filename: 'bundle.js'\n  }\n};\n```\n\nEsto es puramente JS, por lo que podemos escribir Código Real adentro.\n\n## 3. Como llamar a webpack\n\nEntrar al directorio que contiene `webpack.config.js` y ejecutar:\n\n  * `webpack` para construir una vez para desarrollo\n  * `webpack -p` para construir una vez para producción (minificado)\n  * `webpack --watch` para construir de forma continua e incremental en desarrollo (rápido!)\n  * `webpack -d` para incluir mapas fuente (source maps)\n\n## 4. Lenguajes Compilables-a-JS\n\nEl equivalente en webpack para las transformaciones de browserify y los plugins de RequireJS, es un **cargador (loader)**. Aquí vemos como podemos hacer que webpack cargue soporte para CoffeeScript y JSX+ES6 (debes ejecutar `npm install babel-loader coffee-loader` primero):\n\nVer también las [instrucciones de instalación babel-loader](https://www.npmjs.com/package/babel-loader) para dependencias adicionales (tl;dr ejecutar `npm install babel-core babel-preset-es2015 babel-preset-react`).\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: './main.js',\n  output: {\n    filename: 'bundle.js'\n  },\n  module: {\n    loaders: [\n      { test: /\\.coffee$/, loader: 'coffee-loader' },\n      {\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        query: {\n          presets: ['es2015', 'react']\n        }\n      }\n    ]\n  }\n};\n```\n\nPara habilitar requerir archivos sin especificar la extensión, hay que agregar el parámetro `resolve.extensions` declarando que tipos de archivos va a buscar webpack:\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: './main.js',\n  output: {\n    filename: 'bundle.js'\n  },\n  module: {\n    loaders: [\n      { test: /\\.coffee$/, loader: 'coffee-loader' },\n      {\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        query: {\n          presets: ['es2015', 'react']\n        }\n      }\n    ]\n  },\n  resolve: {\n    // ahora podemos hacer require('file') en vez de require('file.coffee')\n    extensions: ['', '.js', '.json', '.coffee']\n  }\n};\n```\n\n\n## 5. Estilos (CSS) e imágenes\n\nPrimero actualizamos el código para incluir contenido estático usando `require()`\n\n```js\nrequire('./bootstrap.css');\nrequire('./myapp.less');\n\nvar img = document.createElement('img');\nimg.src = require('./glyph.png');\n```\n\nCuando requerimos CSS (o less, etc), webpack incluye el CSS en forma de string en una linea dentro del paquete de JS, y `require()` va luego a insertar los tags de estilo `\u003cstyle\u003e` en la pagina. Cuando requerimos imágenes, webpack incluye una linea en el paquete con la URL de la imagen, y luego la retorna desde el `require()`.\n\nUna vez mas, debemos indicarle a webpack como realizar esto (nuevamente utilizando cargadores)\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: './main.js',\n  output: {\n    path: './build', // Aquí van las imágenes y JS\n    publicPath: 'http://mycdn.com/', // Esta ruta se utiliza para generar las URLs a por ejemplo, las imágenes\n    filename: 'bundle.js'\n  },\n  module: {\n    loaders: [\n      { test: /\\.less$/, loader: 'style-loader!css-loader!less-loader' }, // usar ! para encadenar cargadores\n      { test: /\\.css$/, loader: 'style-loader!css-loader' },\n      { test: /\\.(png|jpg)$/, loader: 'url-loader?limit=8192' } // URLs base64 en linea para imágenes \u003c=8k, URLs directas para el resto\n    ]\n  }\n};\n```\n\n## 6. Banderas para funciones\n\nCuando tenemos código que queremos despachar unicamente a nuestro ambiente de desarrollo (como extra logging) o ambientes de preproducción (como funciones en alpha para testear internamente), debemos usar globales mágicas:\n\n```js\nif (__DEV__) {\n  console.warn('Extra logging');\n}\n// ...\nif (__PRERELEASE__) {\n  mostrarFuncionOculta();\n}\n```\n\nY luego informar esas globales mágicas a webpack:\n\n```js\n// webpack.config.js\n\n// definePlugin recibe strings crudas y la inyecta, por lo que es posible incluir JS si se desea.\nvar definePlugin = new webpack.DefinePlugin({\n  __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),\n  __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))\n});\n\nmodule.exports = {\n  entry: './main.js',\n  output: {\n    filename: 'bundle.js'\n  },\n  plugins: [definePlugin]\n};\n```\n\nAhora podemos construir usando `BUILD_DEV=1 BUILD_PRERELEASE=1 webpack` desde la consola. Nótese que ya que `webpack -p` ejecuta la función de uglify para eliminar código muerto, cualquier cosa incluida dentro de ese tipo de bloques va a ser eliminado y por ende, no corremos el riesgo de difundir rutas o cogido secreto.\n\n## 7. Múltiples puntos de entrada\n\nDigamos que tenemos una pagina de perfil y una pagina de feed. No queremos que el usuario tenga que descargar el contenido del feed si solo va a visitar el perfil. Entonces creamos múltiples paquetes: creamos un \"modulo principal\" (llamado punto de entrada) para cada pagina:\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: {\n    Profile: './profile.js',\n    Feed: './feed.js'\n  },\n  output: {\n    path: 'build',\n    filename: '[name].js' // La plantilla utiliza los nombres de la entradas definidas arriba\n  }\n};\n```\n\nPara el perfil, insertamos `\u003cscript src=\"build/Profile.js\"\u003e\u003c/script\u003e` en nuestra pagina; y luego lo mismo para el feed.\n\n## 8. Optimizando código en común\n\nEl Feed y el Perfil probablemente comparten bastante código (como React u hojas de estilos y componentes en común). webpack es inteligente: puede darse cuenta que cosas tienen en común y crear un paquete compartido que puede ser cacheado entre paginas:\n\n```js\n// webpack.config.js\n\nvar webpack = require('webpack');\n\nvar commonsPlugin =\n  new webpack.optimize.CommonsChunkPlugin('common.js');\n\nmodule.exports = {\n  entry: {\n    Profile: './profile.js',\n    Feed: './feed.js'\n  },\n  output: {\n    path: 'build',\n    filename: '[name].js' // La plantilla utiliza los nombres de la entradas definidas arriba\n  },\n  plugins: [commonsPlugin]\n};\n```\n\nAgregando `\u003cscript src=\"build/common.js\"\u003e\u003c/script\u003e` por encima del tag de script que agregamos en el paso previo, ya podes disfrutar de cachear el código compartido.\n\n## 9. Carga asincrónica\n\nCommonJS es síncrono pero webpack nos provee una forma de especificar dependencias de manera asincrónica. Esto es util para routers desde el lado del cliente, donde queremos el router presente en todas las paginas, pero no queremos descargar funciones y/o contenido hasta que no sean realmente necesarias.\n\nEspecificamos el **punto de quiebre** donde queremos cargar de forma asincrónica. Por ejemplo:\n\n```js\nif (window.location.pathname === '/feed') {\n  showLoadingState();\n  require.ensure([], function() { // esta sintaxis es extraña pero funciona\n    hideLoadingState();\n    require('./feed').show(); // cuando se llama a esta función, webpack garantiza que el modulo sea accesible de forma sincrónica.\n  });\n} else if (window.location.pathname === '/profile') {\n  showLoadingState();\n  require.ensure([], function() {\n    hideLoadingState();\n    require('./profile').show();\n  });\n}\n```\n\nwebpack va a realizar el trabajo duro y generar **pedazos (chunks)** y cargarlos por nosotros.\n\nwebpack asume que esos archivos están en el directorio madre cuando los cargamos. Podemos usar `output.publicPath` para configurar eso:\n\n```js\n// webpack.config.js\noutput: {\n    path: \"/home/proj/public/assets\", // ruta donde webpack va a construir tus archivos\n    publicPath: \"/assets/\" // ruta que va a ser utilizada a la hora de requerir archivos\n}\n```\n\n## Recursos adicionales\n\nPara echar un vistazo a un ejemplo del mundo real sobre como un equipo exitoso esta utilizando webpack: http://youtu.be/VkTCL6Nqm6Y\nEs Pete Hunt (autor de esta guía) en la OSCon hablando sobre webpack en Instagram.com\n\n## FAQ\n\n### webpack no parece modular\n\nwebpack es **extremadamente** modular. Lo que hace grandioso a webpack es que permite que los plugins se inyecten a si mismos en mas puntos durante el proceso de construcción, cuando lo comparamos con las alternativas como browserify y RequireJS. Muchas cosas que parecen parte del núcleo son en realidad simplemente plugins que son cargados por default, y pueden ser anulaos o sobrescritos (por ejemplo, el parseador para require() de CommonJS).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetehunt%2Fwebpack-howto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpetehunt%2Fwebpack-howto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetehunt%2Fwebpack-howto/lists"}