webpack菜鸟指南(Beginner’s guide to Webpack)

webpack初学者指南(Beginner’s guide to Webpack)

Beginner’s guide to Webpack
Or what I wish I knew when starting with Wepback.

“webpack初学者指南
或者说当我开始学习webpack的时候,我想了解的”


本文翻译自Nader Dabit的文章,原文地址

https://medium.com/@dabit3/beginner-s-guide-to-webpack-b1f1a3638460#.hl27r5tvz
注:由于我英语水平有限,所有内容都是提供双语,大家可自行核对。
我在学习时的所有源码都可以在 https://github.com/PHPLARAVEL/webpack-react-starter.git
下载


Click here to go to the final Github repo.

Webpack is the latest and greatest in front-end development tools. It is a module bundler that works great with the most modern of front-end workflows including Babel, ReactJS, CommonJS, among others. As a beginner to Webpack, this is what I have learned.

This tutorial has been updated to use Babel 6
点击这里获取最新的源代码(本文的源代码都在这里,如果仅仅想了解下可直接下载源码,推荐使用node命令自己安裝包)
webpack在前端中最新和最伟大的工具之一.webpack是一个模块儿打包工具,它可以很好的与最新的前端开发流程包括Babel,ReactJs,CommonJS等等.作为一个webpack的初学者,这些是我们必须要了解的.
这个小教程已经更新并使用了Babel 6.


Getting Started

Webpack Conventions

Webpack works best with NPM, not Bower
Uses a module system (AMD, CommonJS, ES6)

Installing Webpack globally:

npm install webpack -g

开始啦

Webpack公认约定

webpack最好使用npm而不是Bower
使用模块化系统(AMD,CommonJs,ES6)

全局安装Webpack

npm install webpack -g


The most basic of builds:

In your root directory create 2 files: index.html & app.js

In app.js:

document.write('welcome to my app');

console.log('app loaded');

In index.html:

<html>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

Open your console, and run:

webpack ./app.js bundle.js

The above command uses the webpack command (webpack) to reference our app file (./app.js) and the last argument is the name of the file that we want Webpack to create for us (bundle.js).

The above command should have created a file called bundle.js that is our first Webpack bundle! Easy huh?

最简单的构建

在你的网站配置根目录创建两个文件:index.html 和 app.js
在app.js中:

document.write('welcome to my app');

console.log('app loaded');

在index.html中:

<html>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

然后在终端输入:

webpack ./app.js bundle.js

上面这行命令,使用了webpack中的命令webpack.命令中app.js是我们创建的文件,bundle.js是我们希望webpack为我们创建的文件.
执行完这个命令会在帮我们创建一个bundle.js文件,这就是你创建的第一个budle文件啦!还是比较简单吧!


Defining a config file

A configuration file in Webpack is basically a common.js module. The config file is a place to put all of your configuration, loaders (explained later), and other specific information relating to your build.

In your root directory, create a file called webpack.config.js, and add the following code:

module.exports = {
  entry: "./app.js",
  output: {
    filename: "bundle.js"
  }
}

entry — name of the top level file or set of files that we want to include in our build, can be a single file or an array of files. In our build, we only pass in our main file (app.js).

output — an object containing your output configuration. In our build, we only specify the filename key (bundle.js) for the name of the file we want Webpack to build.

Now, to run our app, go to your command line and run the following command:

webpack

Once a webpack.config file is present, the webpack command will build your application based on the configuration made available in the file.

定义一个配置文件

在webpack中的配置文件就是一个基本的common.js模块儿.这个配置文件中描述了所有你的配置项,加载器(稍后解释),和其他的与你的构建具体信息.
在根目录中创建一个文件webpack.config.js,并输入一下code:

module.exports = {
      entry: "./app.js",
      output: {
        filename: "bundle.js"
      }
    }

entry —–我们的构建的最顶层文件,可以是一个文件,也可一用数组声明一组多个文件.在这该小教程中,我们仅使用一个主文件(app.js)
output—-是一个包含了你的输出配置的对象.在我们的构建中,我们仅标明了文件的key,这个文件就是我们希望webpack创建的bundle.js.
现在就可一启动我们的应用,到命令窗中输入

webpack

一旦我们定义了webpack的配置文件,webpack命令就会基于我们定义的可靠的配置来创建应用.


注:后面的每一段较长,采用穿插翻译

Expanding the functionality of our config file and webpack Watchmode

(扩展配置功能和监听模式)

With watchmode, Webpack will watch your files and when one of them changes, it will immediately rerun the build and recreate your output file.
利用监听模式,Webpack可以监听你的文件,当其中一个文件发生变化,它就会立刻重新构建并生成你的输出文件
There are 2 ways to enable watchmode
有两种方式可以实现监听

1,From the commmand line

1,直接在命令中输入:

webpack --watch

根据我的操作结果理解,这里使用webpack –watch后当你改变你的文件后,你的bundle文件内容不会立马改变,重构的bundle文件存在内存中,当你刷新浏览器时就可以看见改变了.所以这里只有监听,并没有热加载.改变bundle文件内容实在加载后将内存的数据更新到bundle中的

2.Go into the config file, and add a key called watch, and set it to true

2,在配置文件中,增加一个叫”key”的键,并赋值”true”

module.exports = {
  entry: "./app.js",
  output: {
    filename: "bundle.js"
  }, 
  watch: true
}

After watch is set to true, when you run the webpack command, webpack will rebuild your bundle when any of your files change.
当”watch”赋值为”true”后,回到webpack命令中,webpack会在任何文件发生变化时重新构建你的bundle,

此处和上面一样

Webpack Dev Server

Webpack has a web server called webpack-dev-server.
Webpack有一个网络服务叫webpack-dev-server
From the command line, install webpack-dev-server globally:
可以在命令行中全局安装

npm install webpack-dev-server -g

From the command line, run the following command:
在命令行中输入
webpack-dev-server

If you go to http://localhost:8080/webpack-dev-server/, you should see your application running there, along with any log statements in your app.
现在你去 http://localhost:8080/webpack-dev-server/,就会看你的应用跑起来了,并输出了所有的日志信息.

webpack菜鸟指南(Beginner’s guide to Webpack)

From the webpack docs:
从webpacp文档中:

“The dev server uses Webpack’s watch mode. It also prevents webpack from emitting the resulting files to disk. Instead it keeps and serves the resulting files from memory.” — This means that you will not see the webpack-dev-server build in bundle.js, to see and run the build, you must still run the webpack command.

这个开发服务器用了Webpack的监听模式.它也防止webpack输出结果结果到硬盘.取而代之的是,将所得的文件从内存中保存.

这就是说你不会看到 webpack-dev-server 构建bundle.js,要查看和运行这个构建,你必须运行webpack命令

With Webpack dev server running, you will notice that if you go back to your app and make a change, the browser will automatically refresh (hot-loading).
当Webpack开发服务器运行时,你将会发现,如果回到应用改动一下文件,浏览器就会自动的刷新(这就是”热加载”)
The default is to have hot-loading enabled. To disable hot-loading and remove the App Ready status bar at the top, remove the /webpack-dev-server/ from the url, and go to http://localhost:8080/ .
默认hot-loading是开启的,要想关闭hot-loading 和 从顶层移除程序的就绪状态,就删除”/webpack-dev-server/ “,直接访问 http://localhost:8080/
To enable hot-loading and remove the App Ready status bar at the top, terminate the webpack-dev-server and rerun webpack-dev-server with the inline flag:
要开启”热加载”并在顶层移除应用的就绪状态,关闭webpack开发服务器,并在命令行输入:

webpack-dev-server --inline 

Navigate to http://localhost:8080/
去查看这个地址

Now you will see that hot-loading is still enabled, but the status bar is now removed.
Building multiple files
你会发现”热加载”仍然有效,但状态栏却没有了

这个”热加载”还是挺好玩的,结合phpstorm写完代码不用自动保存,浏览器启动更新.就是在实际项目中,都不能用这个服务,不知到有没有其他方法可以让浏览器自动刷新,因为还有php.要是全部是js就应该没问题了

Building multiple files

Building multiple files

1.Requiring files

1.加载文件

Add a file called logger.js to your project.
添加logger.js文件到项目中

In logger.js, add the following code:
在logger.js中输入

console.log('logger.js is now loaded...');

In app.js, add the following to require the logger.js file at the very top before any other code:
在app.js文件顶部中,增加下面的代码去加载logger.js文件

require('./logger');

Now, close and rerun webpack-dev-server, you should see ‘logger.js is now loaded’ being logged to the console when you reload http://localhost:8080/webpack-dev-server/.
现在关闭再重新回到webpack开发服务器,当你重新加载http://localhost:8080/webpack-dev-server/时,你会看到’logger.js is now loaded’ 已经被添加日志到 console 中.

这里根据我的操作,如果开启了热加载,添加完文件后是不需要关闭并回到webpack服务器的,也不需要重新加载,你就可以看到新增的日志信息

2.Adding an additional entry file to our webpack.config.js file

2.增加一个入口文件到配置文件

Add a file called global.js to your project.
增加一个名叫global.js的文件到你的项目中

In global.js, add the following code:
在global.js中,增加下面的代码

console.log('global.js is now loaded...');

Now, open webpack.config.js, and make the entry key an array:
现在,打开webpack.config.js,并且将入口配置键设置成如下数组:

module.exports = {
  entry: ["./global.js", "./app.js"],
  output: {
    filename: "bundle.js"
  }
}

Now, close and rerun webpack-dev-server, you should now also see ‘global.js is now loaded’ being logged to the console when you reload http://localhost:8080/webpack-dev-server/.
关闭并再次启动webpack-dev-server,刷新http://localhost:8080/webpack-dev-server/,你会发现’gloabal.js’已经加载并输出了日志.

Webpack loaders and preloaders

Webpack 加载器和预加载器

Loaders are how Webpack learns new functionality.
加载器是webpack用来扩展新的放的方法的

From the documentation: “Loaders allow you to preprocess files as you require() or “load” them. Loaders are kind of like “tasks” are in other build tools, and provide a powerful way to handle frontend build steps. Loaders can transform files from a different language like CoffeeScript to JavaScript, or inline images as data URLs. Loaders even allow you to do things like require() css files right in your JavaScript!”
文档中这样讲:

加载器可以让你在require()或者加载文件时预先处理这些文件.加载器有些像其他编译器里面的”任务”,在处理前端编译步骤方面提供了强大的功能.加载器可以将不同的语言进行转换,例如将CoffeeScript转换为JavaScript,或者内联的图片文件转换为Urls数据.加载器甚至可以让你做一些如通过require()方法来加载css到你的JavaScript中1
Below, we will install and use two loaders: Babel and JSHint. Before we start using these loaders, we will install a few npm modules. First, use npm init (answer yes to all questions) to create a package.json file. Then in the terminal, type the following:
下面,我们将安装和使用两种装载机:babel和jshint。在我们开始使用这些装载机前,我们会安装一些NPM模块。首先,使用NPM init(当提示你要输入一些信息时,全部选”yes”)来创建一个package.json文件。然后在终端,键入以下内容:

npm install babel-core babel-loader jshint jshint-loader node-libs-browser babel-preset-es2015 babel-preset-react webpack  --save-dev

babel-core is the babel npm package
babel-core是babel的npm模块
babel-loader is the babel module loader for Webpack
babel-loader是babel模块的webpack加载器

jshint is a tool that helps to detect errors and potential problems in your JavaScript code
jshint可以帮助检JavaScript代码测错误和潜在问题的工具
jshint-loader is the jshint loader module for Webpack
jshint-loader是jshint的webpack加载器

node-libs-browser is a peer dependency of Webpack. It provides certain Node libraries for browser usage.
node-libs-browser和webpack是相互依赖的,它为浏览器的使用提供了特定的Node库

babel-preset-es2015 is a babel preset for all es2015 plugins.
babel-preset-es2015可以为所有es2015插件进行babel预设
babel-preset-react is a babel preset for all React plugins.
babel-preset-react可以为所有React插件进行babel预设

— save-dev saves these modules as development dependencies
— save-dev将这些模块保存为开发依赖项

Using Babel with Webpack:

结合Babel使用Webpack::

Now that we have babel installed, let’s write some es6, then include the babel loader.
现在我们已经安装好了babel,我么可以写一些es6代码,然后配置babel的加载器.
Open logger.js. Delete the console.log statement, and replace it with the following:
打开logger.js.删除console.log的这段代码,改成下面的代码:

let checkName= (firstName, lastName) => {
 if(firstName !== 'nader' || lastName !== 'dabit') {
   console.log('You are not Nader Dabit');
 } else {
    console.log('You are Nader Dabit');
  }
}

checkName(‘nader’, ‘jackson’);

  1. Rename logger.js to logger.es6
    2.将logger.js改成logger.es6

  2. Open webpack.config.js and add babel loader. To add a loader in Webpack, you must first create a key named module that is an object. In the module object, create a key named loaders that is an array. In the array, create an object for each loader. Below we have added the configuration for the babel-loader:
    3.打开webpack.config.js并添加babel加载器.在Webpack中增加一个加载器,你必须要先创建一个叫module的key,而module十一个对象.在这个对象中,增加一个key叫loader,它十一个数组.在这个数组中,为每一个加载器创建一个对象.下面已经为babel加载器添加了配置信息:

    module.exports = {
     entry: ["./global.js" , "./app.js"],
     output: {
       filename: "bundle.js"
     },
     module: {
       loaders: [
         {
           test: /\.es6$/,
           exclude: /node_modules/,
           loader: 'babel-loader',
           query: {
             presets: ['react', 'es2015'] 
           }
         }
       ]
     },
     resolve: {
       extensions: ['', '.js', '.es6']
     },
    }
    

As you can see above, we have added three keys to our first loader.
正如你所见到的,我们已经为我们的第一个加载器添加了三个键名

test — a regular expression that tests what kind of files to run through this loader. As you can see, we have added a regex to test all files with an es6 extension.
test–一个正则表达式,用来检测那些文件需要通过加载器处理.如你所见,我们添加了一个表达式检测所有扩展名为”es6”的文件.

exclude — which files the loader should exclude /ignore. We have added the node_modules folder.
exclude (排除)–那些文件加载器将会排除或者说忽略的.我们添加了node_modules这个文件夹.
loader — the name of the loader we are going to use (babel-loader).
loader(加载器)–我们将要使用的加载器(这里是babel-loader)
query — You can pass options to the loader by writing them as a query string or by using the query property as we have done above.
您可以通过将它们写成查询字符串或使用查询属性作为选项传递给给加载程序
cacheDirectory — Default false. When set, the given directory will be used to cache the results of the loader. Future webpack builds will attempt to read from the cache to avoid needing to run the potentially expensive Babel recompilation process on each run
cacheDirectory (缓存目录)–默认为false,当设定后,该文件家将作为加载器的结果.以后webpack的整个构建会尝试从这个缓存目录中读取以避免在每一次运行的潜且费时的Babel重新编译过程
presets — lets us use the react and es2015 presets that were installed earlier
presets –让我们使用之前安装的react和es2015预置

We have also added a key named ‘resolve’ to our module.exports object. resolve is a section which lets us specify what kind of file types we can process without specifically giving them a file extension. This will allow us to use syntax such as:
我们还添加了一个名为”resolve”的key到我们的配置文件的 module.exports对象中.resolve可以让我们表明那些文件在编程时不许要特别的表明文件扩展名.让我们可以进行如下的表达式:

require('./logger');

instead of:
来替换
require(‘./logger.es6’);

We have given ‘resolve’ a key of ‘extensions’ which takes an array of extensions, and we have passed three types of extensions.
我们已经给‘resolve’ 添加了一个”extensions”key,我们给这个数组添加了三个类型的扩展名

We are now ready to rerun Webpack in our project. Close and relaunch the webserver by typing webpack-dev-server, and you should see the new console.log statement of “You are not Nader Dabit”.
回到项目的Webpack.关闭并通过键入 webpack-dev-server重新启动网络服务器,你会在编译输出框中看到”You are not Nader Dabit”
Congrats, you are now running babel with Webpack!
恭喜!你现在已经将babel和Webpack结合使用啦!

Preloaders: Using JSHint with Webpack:

We will be utilizing JSHint as a preloader. As you could have probably guessed, preloaders run before loaders do. Change your webpack.config.js to the following, including the preLoaders key:
我们将用 JSHint 作为一个预加载器.如你所想,预加载器在加载器之前运行.首先,对你的webpack.config.js文件增加一个preLoaders的键,如下:

module.exports = {
 entry: ["./global.js" , "./app.js"],
 output: {
   filename: "bundle.js"
 },
 module: {
   preLoaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'jshint-loader'

      }
   ],
   loaders: [
     {
       test: /\.es6$/,
       exclude: /node_modules/,
       loader: 'babel-loader',
       query: {
          cacheDirectory: true, 
          presets: ['react', 'es2015'] 
       }
      }
   ]
 },
 resolve: {
   extensions: ['', '.js', '.es6']
 }
}

Close and rerun webpack-dev-server. You should see an error message:
关闭并重启 webpack-dev-server.你就可以看到一个错误信息

The warning is an eval error, and it means jshint is running!
该警告是一个求值错误,表明jshint已经在运行了

Creating a Start Script

创建一个启动脚本

This is actually a feature of npm and the functionality you can use in your package.json file, but it is something worth doing to make your process easier.
这实际上是一个npm的特性和可以在package.json文件中使用的方法,它可以是你的编程变得更简单
In package.json, there is a key called scripts. Delete the contents of the scripts key, and replace it with the following:
在你的package.json文件中,有意个叫做scripts的key.删除该key的值,并替换成如下内容:

"scripts": {
  "start": "webpack-dev-server"
},

Now when we need to run webpack-dev-server, we can run the following instead:
现在,当你需要运行webpack-dev-server,你可一执行下面的命令来替换:

npm start

This will make more sense in the future as we add more options into our webpack-dev-server command, and make it easier to rerun often, but is still nice to have even now.
Separate production and development Builds
当我们在以后的开发中需要在webpack-dev-server执行更多的命令时,这个方法将更有意义.

Separate production and development Builds

将开发和生产构建拆分开

Production Webpack bundles

生产环境的Webpack构建

To run a production bundle, letting webpack minify your code, run Webpack with a -p flag:
运行生产的构建,用webpack压缩你的代码,可以在使用Webpack命令时加上 -p 参数

webpack -p

This will produce a minified bundle.
这样就会生成一个压缩后的构建
Working with different config files for production vs development
在工作时我们可以创建不同的配置文件,来对应的生成生产的和开发的构建
Install strip-loader:
安装strip-loader:

npm install strip-loader --save-dev

strip-loader is a loader to strip arbitrary functions out of your production code (we will use this later) .
strip-loader是一个可以用来从你的生产构建的代码中删除指定函数的加载器(我们稍后就将使用)
Create webpack-production.config.js
创建一个webpack-production.config.js文件

In webpack-production.config.js, write the following code:

var WebpackStripLoader = require('strip-loader');
var devConfig = require('./webpack.config.js');

var stripLoader = {
 test: [/\.js$/, /\.es6$/],
 exclude: /node_modules/,
 loader: WebpackStripLoader.loader('console.log')
}

devConfig.module.loaders.push(stripLoader);

module.exports = devConfig;
  1. WebpackStripLoader — we require the strip-loader npm module

  2. WebpackStripLoader —加载strip-loader这个npm模块

  3. devConfig — we require the original webpack configuration file

  4. devConfig — 加载原生的webpack配置文件

  5. var stripLoader — we create a new object, and pass in the test and exclude keys as seen before. Worth noting is the

  6. var stripLoader — 创建一个新的项目,和之前一样增加了test键和exclude键.有用的就是下面这一句

    loader:WebpackStripLoader.loader('console.log')
    

line. Here we are asking strip-loader to remove any console.log statements from our
build. WebpackStripLoader.loader() takes any number of arguments.
我们告诉 strip-loader 从构建中删除任何使用了console.log句子.WebpackStripLoader.loader() 可以添加任意数目的参数
4. devConfig.module.loaders.push(stripLoader); — we push the new object into our loaders array from our original config.
我们将新的对象添加到配置文件中(该配置文件为原生的配置文件)
5. module.exports = devConfig; — we export our new config object
生成新的配置文件对象
In the terminal, run:
在终端,运行:
webpack –config webpack-production.config.js -p

这里在我的操作中发现,如果使用上面的命令,似乎不会启动网络服务,运行
webpack-dev-server –config webpack-production.config.js -p 就行了

This runs webpack with the config flag, letting us specify a custom config file. -p minifies the code for production.
运行webpack并增加config参数,可以让我们指定自定义的配置文件. -p 压缩生产环境的代码

Open bundle.js. If you do a find and replace you will notice there are no console.log statements in our bundle.
打开bundle.js.你可以用查找来检测,这里面没有console.log的语法.

Implementing React with Webpack

将React和Webpack结合使用

Now that we have Webpack configured, let’s add React.
我们已经将Webpack配置好了.,现在结合React
First, install react by going to the terminal and entering:
首先,在终端输入以下命令安装

npm install react --save

Next, create a file named hello.js, and enter the following code:
接下来,创建一个 hello.js文件,添入一下代码:

import React from "react";

export default React.createClass({
 render: function() {
   return (
     <div>
         Hello, {this.props.name}!
     </div>
   );
 },
});

Open app.js. Remove the contents of app.js, and replace with the following:
打开app.js.删除app.js的内容,替换成如下代码,

import React from "react";
import Hello from "./hello";

React.render(
 <Hello name="World" />,
 document.body
);

Open webpack.config.js, and change the babel-loader test key to the following array:
打开 webpack.config.js,改变 babel-loader的test键为如下的数组:

loaders: [
   {
     test: [/\.js$/, /\.es6$/],
     exclude: 'node_modules',
     loader: 'babel-loader'
   }
 ]

This allows for both .js and .es6 files to be passed to babel, letting us use jsx in our code.
这样,我们可以让.js和.es6文件都通过babel编译,是我们可以使用jsx语法

Rerun webpack-dev-server, and you should see the following:
重新运行webpack-dev-server,你就会看到效果啦!

注:翻译时React版本是0.14.7的,所以需要安装react-dom

npm install react react-dom –save,

然后在app.js和hello.js中的加载react的下面添加,

import ReactDom from “react-dom”;

运行后如果提示document.body警告,则需要将app.js中的

ReactDom.render(
    <Hello name="World" />,
    document.body
);

替换成

ReactDom.render(
        <Hello name="World" />,
        document.getElementById('main')
    );

并将index.html修改为:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="main"></div>
        <script src="bundle.js"></script>
    </body>
</html>

The final source is available for download here.
最终的代码资源可以在这里下载

Thanks for reading, please let me know if you have any questions!
谢谢阅读,如有疑问,请留言!

My Name is Nader Dabit @dabit3. I am a developer at @schoolstatusapp. If you enjoyed this article, please recommend and share it! Thanks for your time.
我的名字加叫 Nader Dabit @dabit3.我是一个@schoolstatusapp的程序员.如果你新欢这篇文章,请推荐并分享它.谢谢!