最初翻译于2017年1月初,后来以为翻译的很差就删掉了...如今恢复~ 说不定对别人有帮助javascript
简而言之,webpack是一个JavaScript模块打包工具。可是它能够用来托管而且管理你全部的前端代码(至少它被开发出来的目的或者说社区但愿达到的目标是这样的)css
传统的构建工具执行任务的方式是: 你的css以及javascipt等是分离的。你必须分开的去管理他们,而且你要确保每一项在生产环境中都是合适的状态。html
好比gulp能够担当预处理器和转换器的角色,可是每个场景下,它都会有源输入(目录或者文件)和一个编译打包后的目标输出(目录或者文件)。可是它仅仅是按照这个规则一个接着一个的执行却没有在宏观上去考虑如何和整个应用更好的结合。这会给开发者带来一些负担:如何选择以及怎样筛选合适的任务处理器;在生产环境中去将这些分离的部件很好的啮合到一块儿。前端
Webpck抛出一些问题: 若是在开发的过程当中某一个工具会自行帮咱们处理应用中模块之间的依赖, 咱们只须要专一在咱们本身的业务代码层面以及最终产出,构建只须要通过简单的配置 那么状况会变得怎么样呢?java
webpack的处理方式: 若是webpack知道你想要什么,他只会打包生产环境中实际用获得的模块。node
若是你在最近几年活跃在各大web社区,我想你已经知道了解决问题的办法了: 使用javascript来实现。 Webpack尝试去使用javascript来处理模块之间的依赖使构建过程更加简单。 可是这个设想强大的地方不是仅仅的模块管理,而是整个构建层面100%是由javascript来实现,伴随node的特性,它能够作的更多。Webpack让你可以写出更契合系统的有效的javascript代码。python
换句话说:你没必要为webpack编写代码,单纯的for your project。
可是webpack可以和你的项目完美共生(固然须要增长一些额外的配置,若是你的项目有新的构建需求)react
简而言之, 若是你曾经被下面的问题困扰过:webpack
那么webpack应该会帮助到你,上面提到的问题,它都能经过javascript来解决。最棒的是什么? Webpack能够纯粹的在服务端运行,这意味着你可使用webpack来开发渐进加强(progressively-enhanced)的websites。es6
咱们使用的是Yarn(brew install yarn),没有用npm,这不影响咱们的后面的demo,他们达到的目的是同样的。咱们在执行下面的命令,将webpack添加到全局module和本地项目中。
yarn global add webpack@beta webpack-dev-server@beta
yarn add --dev webpack@beta webpack-dev-server@beta
咱们新建一个webpack配置文件,在咱们项目的根目录下面
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
app: './app.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
};
Note: __dirname
指向当前项目的根目录
Webpack经过阅读你的代码 能够‘知道’项目中运行的内容(‘别担忧,它签了保密协议的’),webpack作了下面几件事:
context
目录启动, …output.path
目录下面,而且是以output.filename
命名的([name]将会被entry的key替换)。 src/app.js
以下,你须要提早安装moment到项目中(yarn add moment
)
import moment from 'moment';
var rightNow = moment().format('MMMM Do YYYY, h:mm:ss a');
console.log(rightNow);
// "October 23rd 2016, 9:30:24 pm"
而后运行
webpack -p
Note: The p flag is “production” mode and uglifies/minifies output. 这个-p参数 全名字是 production,它会帮咱们压缩输出的文件。
你会看到在dist/app.bundle.js
里面记录了日期时间而且有console语句。注意到webpack自动将moment
引入了,由于app.js文件里面require了这个包。(尽管若是你当前目录有一个moment.js的文件,然而webpack会优先引用Node Module里面的moment module)
You can specify any number of entry/output points you wish by modifying only the entry object.
你能够修改entry对象来指定任意数量的入口/输出文件,entry的值能够是字符串,数组,对象。
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
app: ['./home.js', './events.js', './vendor.js'],
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
};
Will all be bundled together as one dist/app.bundle.js file, in array order. 最终会将这3个文件一块儿打包进disa/app.bundle.js
文件,按照数组的索引来排序
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
home: './home.js',
events: './events.js',
contact: './contact.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
};
固然你也能够选择将多个js文件打包进你的app,在dist目录下会有三个文件 home.bundle.js
, events.bundle.js
,contact.bundle.js
若是你将你的应用分别打包,输出多个文件(若是你的app内部存在巨量的js,而这个js你不须要提早加载这就有必要了),有可能在打包以后的多个文件可能有重复的代码,由于webpack将多个文件内须要的依赖依次打包进了多个目标文件里面。幸运的是 webpack提供了CommonsChunk插件来解决这个问题:
module.exports = {
// …
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js',
minChunks: 2,
}),
],
// …
};
如今,在你的输出目标文件内,若是有任何模块被加载了2次(这个是由参数minChunks
来决定的),那么这个模块将会被打包进一个名字为common.js(看上面代码由参数filename
来决定)这个文件能够缓存到客户端,虽然多一次额外的网络请求,可是这也阻止了客户端屡次下载重复的库。许多状况下都是这样网络换取速度。
Webpack 实际上有它本身的开发服务器,所以不管你正在开发一个静态页面或者作前端原型,它都很是适合。你能够增长一个devServer
对象 在 webpack.config.js
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
app: './app.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './dist/assets'),
publicPath: '/assets', // New
},
devServer: {
contentBase: path.resolve(__dirname, './src'), // New
},
};
在src/index.html
增长下面代码:
<script src="/assets/app.bundle.js"></script>
终端里面运行
webpack-dev-server
你的服务器已经运行在8080端口上。请注意在scipt标签里面的 /assets
,它匹配的是output对象里面的publicPath(相似于express里面的静态目录),你能够任意命名,这一点在cdn加速的时候特别有用。
要用全局命名空间里面的特定函数?在webpack.config.js
里面配置output.library
module.exports = {
output: {
library: 'myClassName',
}
};
…这会在window对象上绑定一个myClassName的实例,如今在入口文件里面能够调用这个实例里面的方法,或者值。
到目前为止,咱们用到的语言仅仅是javascript, 这是必要的由于Webpack使用的惟一语言就是它 webpack自身只能处理javascript模块。可是其余类型的模块和文件(好比sass,css)webpack自身没有办法处理,可是只要咱们将它们通过javascript处理
一次转换成咱们须要的类型。咱们就就它加载器或者转换器。
加载器能够扮演预处理的角色(编译sass),或者转换角色(好比babel,将es6或者React 转换到es5),在npm上,一般他们以 *-loader
的方式命名,好比前面的 sass-loader
和 babel-loader
因为如今es6兼容性问题,咱们想使用es6的特性就得须要babel的转换了,首先咱们要安装合适的加载(转换)器:
yarn add --dev babel-loader babel-core babel-preset-es2015
…而后在webpack.config.js
下面配置
module.exports = {
// …
module: {
rules: [
{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: { presets: ['es2015'] }
}],
},
// Loaders for other file types can go here
],
},
// …
};
对于webpack 1.x
的用户来讲, 加载器的核心概念和2.x来讲是一致的。可是语法有一些变化(好比1.x
中是loaders 而不是rules),由于如今仍然处于发布候选版阶段,因此在正式版文档以前这些语法可能都不是最准确和合适的。
test
的正则对象 /\.js$/
的目的是去寻找babel-loder去加载的全部以.js结尾的文件。Webpack经过这个正则容许开发者去控制那些文件能够被转换或者编译,固然他不会强制你采用那些文件扩展名,只须要你以合适的方式组织你的文件,这个正则匹配到了就好。
好比:在/my_legacy_code/
这个目录下面,你没有使用es6,你能够修改上面test的值 /^((?!my_legacy_code).)*\.js$/
,babel-loader 会过滤掉这个特殊的文件夹,转换其余的文件。
咱们也能够经过css-loader引入css文件,好比咱们当前项目目录有 index.js
文件,咱们能够这样导入
import styles from './assets/stylesheets/application.css';
固然直接这样一句代码是不行的,会报错:You may need an appropriate loader to handle this file type
,记住webpack只能解析javascript,所以咱们要安装合适的loader。
yarn add --dev css-loader style-loader
而后在webpack.config.js里面配置
module.exports = {
// …
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
// …
],
},
};
加载器的执行顺序是数组索引的逆序,这意味着先会运行css-loader,而后再是style-loader.
你会注意到在生产环境下,webpack在打包css的同时也会将css同时打包,style-loader
实际上作的实质性内容就是将你的css代码写入到html里面的head
标签里面。虽然乍看一下以为有点奇怪,可是慢慢的你会发现,那实际上是合理的。 试想,你确定作过这样的优化,少向服务端发送一个请求–就节约了网络请求的时间-若是你采用js加载dom的方式,本质上也就避免Flash of unstyled content
。(参考地址:https://en.wikipedia.org/wiki/Flash_of_unstyled_content)
你也会注意到,webpack会自动的将@import 队列里面css文件打包成一个(并不是像css默认的importy引入方式,它会增长更多的请求下降加载静态资源的速度)
在js文件中加载css是很是棒的,由于你能以一种新的方式模块化你的css。你能够在button.js里面引用button.css,这意味着若是button.js没有被使用,那么button.css里面的样式永远不会出如今生产环境中。若是你很是推崇css组件模块化这一套体系好比 SMACSS 或者BEM(参考地址:https://smacss.com/book/categorizing),你在编写css与你和js的时候发现它的精妙所在。
想使用sass,没问题
yarn add --dev sass-loader node-sass
增长以下规则:
module.exports = {
// …
module: {
rules: [
{
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
]
}
// …
],
},
};
这样在js文件中能够经过import引入sass或者scss文件了。
若是你想将css打包进一个单独的文件,而不是依赖bundle将样式以style写入在head
标签里面。咱们可使用webpack插件extract-text-webpack-plugin
来实现,打开app.js
import styles from './assets/stylesheets/application.css';
安装这个插件到本地目录
yarn add --dev extract-text-webpack-plugin@2.0.0-beta.4
在webpack.config.js
增长以下配置:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
// …
module: {
rules: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
loader: 'css-loader?importLoaders=1',
}),
},
// …
]
},
plugins: [
new ExtractTextPlugin({
filename: '[name].bundle.css',
allChunks: true,
}),
],
};
在终端运行webpack -p
你会发如今output设置的目录里面生成了一个app.bundle.css
文件,这时候在html文件里面增长link引入css文件,打开html,和预期的同样。
翻译自: https://blog.madewithenvy.com/getting-started-with-webpack-2-ed2b86c68783#.qdh8mzhl0
参考资料: https://webpack.js.org/configuration/