什么是 Webpack

js 代码的模块打包工具(原初) → → 前端代码的管理工具.(现在)

  • 旧方式: html css js 都是分离的.必须分别对每一项进行管理.

安装和配置

一: 全局安装

  1. 安装 webpack 全局环境 : npm install webpack -g
  2. 查看 webpack 版本: webpack -v

    webpack 是 node 项目. 确保电脑有安装 node.js & npm

二: 项目安装

  1. 终端进入项目路径
  2. 确保有 package.json (没有就 npm init 一路回车来创建.) 终端进入到项目文件夹. → npm init // 就是创建/修改 package.json 的命令. 不会影响别的文件 → name: (cms) // 回车.会显示当前文件夹的名字. → version: (1.0.0) // 回车.. → description: // 回车 (让你添加描述的…) → entry point: (highlight.js) // 回车 后面可以改的…. → ….. // 一路回车!!!!

  3. 安装 webpack 依赖 npm install webpack –save-dev

     // 下面是上面命令的缩写( 选一个就行.)
     // -save :     模块名将被添加到dependencies.    可以简化成参数 -S
     // -save-dev:  模块名将被添加到devDependencies,可以简化为参数 -D
     npm i webpack -D
    
  4. package.json 参考: // 参考1 { “name”: “first-demo”, “version”: “1.0.0”, “description”: “this is my first-demo”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “author”: “guowenfh”, “license”: “MIT”, “dependencies”: {}, “devDependencies”: { “webpack”: “^1.12.14” } }

     // 参考2
    	
     {
       "name": "cms",
       "version": "1.0.0",
       "description": "> 大类: 不能有英文的.; (可以有:-)不然不能过滤出对应标签&文章.   > 标签: 不能有下划线; 不能有空格(有空格就是多标签了.本主题不支持)",
       "main": "index.js",
       "dependencies": {
     "minimatch": "^3.0.3"
       },
       "devDependencies": {
     "webpack": "^2.2.1"
       },
       "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
       },
       "author": "",
       "license": "ISC"
     }
    
  5. package.json 作用
  • 为npm 提供一切信息.
  • 告诉node 怎样处理一个包.
  • 为人们查看项目提供一个进入点

开发者可以通过 这个文件 了解很多关于我们项目的信息. 最重要的是 可以看出我们应用的进入点是 什么…

创建一个简单的包进入点

新建文件: index.js: 文件内容: `console.log(“xu.jian”); `

. 运行方法1: 用node直接运行脚本

$node index.js   
xu.jian 

运行方法2: 用 require 在其他地方引用脚本

  • 首先进入 node的交互界面: (终端: 输入 node, 然后按回车就进去了)
  • 输入 require('./index') 然后回车

  • 实例代码: ➜ cms git:(master) ✗ node index.js hello xu.jian ➜ cms git:(master) ✗ node

    require(“/index”) Error: Cannot find module ‘/index’ at Function.Module._resolveFilename (module.js:470:15) at Function.Module._load (module.js:418:25) at Module.require (module.js:498:17) at require (internal/module.js:20:19) at repl:1:1 at realRunInThisContextScript (vm.js:22:35) at sigintHandlersWrap (vm.js:98:12) at ContextifyScript.Script.runInThisContext (vm.js:24:12) at REPLServer.defaultEval (repl.js:313:29) at bound (domain.js:280:14) require(“./index”) hello xu.jian {} require(“./index”) {} require(“./”) {}

  • 实例解析: 这里 最后的 {} 是require的返回值. node 允许我们省略.js 扩展名. 因为运行的就是js.. 如果我们这这个交互界面中 继续运行 require(“./index”) 我们将得到相同的返回值但是不会得到console.log输出, 因为require不会再同一个脚本中运行两次. ./ 是当前文件夹的意思. 非常重要. 点必须有.

下面回到 package.json “main”: “index.js” 当你 require 一个含有package.json 文件的文件夹时候. node 会默认你require package.json 里的 main 参数后面的文件.

require(“./index”) {} 两者等价 require(‘./’) {}

第一个npm模块: colors

让你的 node.js console 带上颜色.

突然npm命令没有了 折腾半天才发现 要用cnpm… Warning: node-7.5.0 already installed, it’s just not linked.

终端cs项目文件夹(直接运行就行): $ cnpm install –save colors 然后去看 package.json dependencies 下面应该多了个 “colors”: “0.6.0-1” 这个就是 –save 的作用.

colors 模块使用方法

要引入的… 不是你输入任何东西都会自动高亮的. var colors = require(‘colors’);

console.log('hello'.green); // outputs green text
console.log('i like cake and pies'.underline.red) // outputs red underlined text
console.log('inverse the color'.inverse); // inverses the color
console.log('OMG Rainbows!'.rainbow); // rainbow
console.log('Run the trap'.trap); // Drops the bass

使用实例(这里颜色没显示处理.去终端肯定有颜色的.) ➜ cms git:(master) ✗ node

var colors = require(‘colors’); undefined console.log(‘hello’.green); hello undefined console.log(colors.red.underline(‘i like cake and pies’)) i like cake and pies undefined console.log(colors.inverse(‘inverse the color’)) inverse the color undefined console.log(colors.rainbow(‘OMG Rainbows!’)); OMG Rainbows! undefined console.log(colors.trap(‘Run the trap’)); ЯՍÑ ͳԊƎ ŦȐȺҎ undefined

重写 index.js (进一步了解依赖模块)

  1. 把 index.js 内容替换成下面的. var colors = require(‘colors’); console.log(‘Hello,’.red, ‘npm!’.green);

  2. 终端用 node 运行 index.js 输出的 hellp npn 在终端里就会变成多彩的.只是博客里没颜色而已. ➜ cms git:(master) ✗ node index.js Hello, npm!

node_modules 的层级 require 怎么知道去哪找 colorss.js 模块呢. node 首先查找本地项目下的 node_modules文件夹(隐藏的). 使用 npm install 安装任意包的时候被自动创建. 如果本地项目没有 colors.js 那就会查找上一级的. 没有再查找上一级的 .知道系统的根目录..

npm收尾工作 如果我要和全世界分析 hello-npm 项目. 我会push到 github .再npm registry 中发布我的包. 由于全世界只能有一个叫 npm-hello的包. 你要注册一个账户..然后改个包名字. 就可以了…

发布好之后 就可以用下面命令来安装了: $npm install hello-npm

到这里环境就安装好了. package.json里也有了 webpack

第一个 webpack 打包程序

创建一个静态页面: index.html 创建一个 js 入口文件: entry.js 名字随意. 打包的时候 对应就可以.

index.html <html> <head> </head> <body> <h1 id="app"></h1> </body> </html>

entry.js document.getElementById(‘app’).innerHTML=”这是我第一个打包成功的程序”;

然后 执行 webpack entry.js bundle.js

//就个 必须在 本地搭建的html中执行. // 博客文件夹中执行会报错.. 不知为啥, 我用的是 MAMP Pro. 搭建环境很方便. ➜ webpack webpack entry.js bundle.js Hash: fa8c4054e08d59170d93 Version: webpack 2.2.1 Time: 70ms Asset Size Chunks Chunk Names bundle.js 2.57 kB 0 [emitted] main [0] ./entry.js 58 bytes {0} [built] ➜ webpack

本来 html 是空白的. 现在就出来一行字.这是我第一个打包成功的程序 因为 webpack 执行了 js . 把js结果放到html里了.

增加一个文件打包

  1. 新建first.js var h2= document.createElement(“h2”) h2.innerHTML=”不是吧,那么快第二个打包程序啦!”; document.body.appendChild(h2);

  2. 更改 entry.js document.getElementById(‘app’).innerHTML=”这是我第一个打包成功的程序”; //添加 require(“./first.js”);

  3. 运行打包程序: webpack entry.js bundle.js

  4. 下面就可以看出 第一次 第二次的区别了 ➜ webpack webpack entry.js bundle.js Hash: fa8c4054e08d59170d93 Version: webpack 2.2.1 Time: 70ms Asset Size Chunks Chunk Names bundle.js 2.57 kB 0 [emitted] main [0] ./entry.js 58 bytes {0} [built] ➜ webpack webpack entry.js bundle.js Hash: 3bf753e1b1028677c85b Version: webpack 2.2.1 Time: 78ms Asset Size Chunks Chunk Names bundle.js 2.77 kB 0 [emitted] main [0] ./first.js 100 bytes {0} [built] [1] ./entry.js 83 bytes {0} [built] ➜ webpack

webpack 会分析入口文件. 解析包含依赖关系的各个文件. 这些文件(模块)都打包到 bundle.js 中. webpack 会给每个模块发配一个唯一的id. 并通过这个id索引和访问模块 先执行 entry.js 中的代码. 其他模块会在运行 require 的时候再执行.

webpack 二

上面打包了 js 文件. 其实通过loader 还可以处理其他类型的文件.

Loader 介绍

loader 可以理解成 模块和资源的转换器. 本身是一个函数. 接受源文件作为参数. 返回转换的结果. 这样可以通过require来加载任何类型的模块或者文件.

loader 特性

Loader可以通过管道方式链式调用,每个loader可以把资源转换成任意格式并传递给下一个loader,但是最后一个loader必须返回JavaScript。 Loader可以同步或异步执行。 Loader运行在node.js环境中,所以可以做任何可能的事情。 Loader可以接受参数,以此来传递配置项给loader。 Loader可以通过文件扩展名(或正则表达式)绑定给不同类型的文件。 Loader可以通过npm发布和安装。 除了通过package.json的main指定,通常的模块也可以导出一个loader来使用。 Loader可以访问配置。 插件可以让loader拥有更多特性。 Loader可以分发出附加的任意文件。

loader 安装

先安装读取 css 文件的 css-loader. 再用 style-loader 把它插入到页面中.

安装css-loader 和 style-loader

npm install css-loader style-loader --save-dev npm 不行就 用 cnpm

这时就可以看到 package.json 多了 两个 “devDependencies”: { “css-loader”: “^0.26.1”, “style-loader”: “^0.13.1”, “webpack”: “^2.2.1” },

安装方式有很多种. 你也可以package.json 添加对应的依赖名.然后运行 npm install 一样的效果.

加载CSS 文件

添加一个css 文件. style.css body { background: red; }

然后修改 entry.js 原文不变. 添加: require(“!style!css!./style.css”);

继续编译 webpack entry.js bundle.js

刷新页面.背景颜色就变了.

扩展名自动绑定 loader

webpack ./entry.js bundle.js --module-bind "css=style-loader\!css-loader" entry 里. require css 就不需要加前缀了...  

原来: require(“!style-loader!css-loader!./test.css”) 现在: require(“./test.css”);

因为!在命令行中具有特殊的含义,所以我们需要对它进行转义操作。

成功的话,应该能再次看到背景的变化。 虽然这样可以将多个css文件进行编译打包,但是总感觉很是繁琐,我不想每次都运行那么一长串的命令怎么办?继续向下走吧。

webpack 配置详解

webpack 执行命令的时候. 除了可以在 命令行传入参数. 还可以通过指定的配置文件来执行. 默认会搜索 当前目录的 webpack.config.js

entry:

入口文件的配置项. 是一个数组. 允许多个入口. 只有一个入口的话: 直接使用双引号”./entry.js”

output

配置打包结果.
path:定义输出文件夹. filename: 定义打包结果的文件名.

module

对模块的处理逻辑. 这里可以用loader 定义一系列加加载器. 以及一些正则表达式.

当需要加载的文件匹配test的正则时.就会调用后面的 loader 对文件进行处理. 这才是 webpack 强大的原因.

webpack 插件示例

插件可以完成loader不能完成的事情. 插件一般在 webpack.config.js 中的 plugins 中指定

给输出的文件 头部添加注释信息的 内置插件: bannerplugin 来试验

加载图片

  1. 安装对应的loader 它会把样式引用到图片.转为模块来处理. 使用该加载器需要先安装. npm install url-loader –save-dev

  2. img 目录 添加两图片: 大的jpg 小的png.

  3. webpack.config.js 添加:

    loaders: [ { test: /.css$/, loader: “style!css” }, { test: /.(png|jpg)$/, loader: “url-loader?limit=8192” } // 添加到这!并且会按照文件大小, 或者转化为 base64, 或者单独作为文件 //在大小限制后可以加上&name=./[name].[ext],会将我们的文件生成在设定的文件夹下。 ]

在html 中添加: <div id="qwe"></div> <div id="asd"></div>

css中添加: /记得写宽高。。/ qwe{ background-image: url(img/logo.png);/3.2k/ } asd{ background-image: url(img/5.jpg); }

继续运行webpack如果正确的话,打开我们的浏览器,就可以看到我们正确的图片显示。

现在我们打开浏览器的调试工具,可以看到小于8K的 背景图片 图片已经被转化成了base64的编码,而大于8k的图片则并没有转化(注意它的地址的变化!)。 直接使用img导入的图也并没有进行base64的转化。

热加载

项目变大. webpack 编译时间也会变长. 可以通过参数让编译的输出内容带有 进度 和颜色.

webpack --progress --colors

其他命令

webpack #最基本的启动webpack命令
webpack -w #提供watch方法,实时进行打包更新
webpack -p #对打包后的文件进行压缩
webpack -d #提供SourceMaps,方便调试
webpack --colors #输出结果带彩色,比如:会用红色显示耗时较长的步骤
webpack --profile #输出性能数据,可以看到每一步的耗时
webpack --display-modules #默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块

webpack sass

加载css 需要: css-loader 和 style-loader. css-loader 会遍历css文件. 然后找 url()表达式 处理. style-loader 会把css 插入 到页面中.

npm install --save-dev css-loader style-loader
//webpack中配置
module: {
loaders:[
{
test: /\.css$/, // Only .css files
loader: 'style!css' // Run both loaders
}
]
}

如果要用编译CSS: sass-loader less-loader 两种加载器. 这里选择 sass cnpm install –save-dev sass-loader webpack 参考: var path = require(‘path’); var config = { entry: path.resolve(__dirname, ‘app/main.js’) output: { path: path.resolve(__dirname, ‘build’), filename: ‘bundle.js’ }, module: { loaders: [{ test: /.jsx$/, loader: ‘babel’ },

// LESS
{
  test: /\.less$/,
  loader: 'style!css!less'
},

// SASS
{
  test: /\.scss$/,
  loader: 'style!css!sass'
}]
  }
};

less/sass 中的import 怎么办

如果你从另外一个文件中导入一个sass/less 文件. webpack 会找出那些文件. 然后识别里面的依赖.

这样 项目中可以直接使用 import ‘app.scss’

上面的配置会在html生成 style 标签. 不利于开发调试. 一般用下面的:

npm install --save-dev autoprefixer-loader
//webpack中配置
module: {
loaders:[
{
test: /\.scss$/,
loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap'
}
]
}

jekyll webpack js

  1. 项目目录先安装 webpack npm install webpack -g
  2. 梳理项目结构 :
  3. 文件结构没要求. webpack 配置文件 .只要有 entry 和 output 文件夹就可以.

默认文件结构 . ├── _config.yml ├── _includes │ ├── … ├── _layouts │ ├── default.html │ ├── page.html │ └── post.html ├── _posts │ ├── … ├── _sass │ ├── _base.scss │ ├── _layout.scss │ └── _syntax-highlighting.scss ├── about.md ├── css │ └── main.scss ├── feed.xml └── index.html

成品文件结构:

  • 根目录 有 package.json 和 webpack.config.js
  • 多了个 src 目录. … (source: src)
  • 多了个 public 文件夹… (config : destination: public )
  • 多了个 webpack 文件夹. 里面含有 entry.js

      .
      ├── _config.yml
      ├── package.json
      ├── public
      │ ├── …
      ├── src
      │ ├── _includes
      │ │ ├── …
      │ ├── _layouts
      │ │ ├── default.html
      │ │ ├── page.html
      │ │ └── post.html
      │ ├── _posts
      │ │ ├── …
      │ ├── _sass
      │ │ ├── …
      │ ├── about.md
      │ ├── assets
      │ │ ├── css
      │ │ ├── images
      │ │ └── javascripts
      │ │ └── bundle.js
      │ ├── feed.xml
      │ └── index.html
      ├── webpack
      │ ├── entry.js
      │ └── components
      │ └── …
      └── webpack.config.js
    

    这个需要 你要移动 所有 jekyll build 需要的文件移动到 src 目录. 这里由于你把 本地是根目录site文件夹下生成的. 改成了public. 所以你要 用 pow 这个工具来查看效果. pow 软件作用以后再说.简单 的 环境搭建???

  1. 添加 package.json. 没有这个文件 npm 就不知道要运行什么. 也就是npm的配置文件吧.

  2. 添加 webpack 文件夹
  3. webpack 文件夹下 添加 entry.js
  4. 移除里javascripts 文件夹里的所有文件(先到电脑别的地方).保留这个文件夹.
  5. 配置 webpack.config.js module.exports = { // webpack folder’s entry js — excluded from jekll’s build process. entry: ‘./webpack/entry.js’, output: { // we’re going to put the generated file in the assets folder so jekyll will grab it. path: ‘src/assets/javascripts/’, filename: ‘bundle.js’ }, module: { loaders: [ { test: /.jsx?$/, exclude: /(node_modules)/, loader: ‘babel’, // ‘babel-loader’ is also a legal name to reference query: { presets: [‘react’, ‘es2015’] } } ] } };

这个配置文件告诉webpack. 哪里去找入口文件: entry.js 把生成的文件 改成什么名字 .输出到哪个文件夹.

  1. 忽略文件

你必须要 告诉 github 和jekyll 忽略下面的文件夹: node_modules 下的所有文件. 这个很多很多很多文件…. 在 gitignore 里 添加 /src/assets/bundle.js public 和 node.modules 文件夹.

  1. 把 bundle.js 添加到 html 就可以了.

  2. 安装 依赖.

  3. entry.js 放一点内容.可以有输出
  4. build
  5. 下面就是 react了..

总结: 只要把 entry.js 和 first.js 输出成一个. bundle.js 就可以了.

只要修改下 webpack 指定enrtry 入口. 和输出文件夹.输出名字 再引入到 html 就可以了.

doit.

  1. 配置

每个项目下都必须有一个配置文件: webpack.config.js 告诉webpack 需要做什么.

安装

第一步

使用 yarn 来替代 npm (两个功能一样 但是教程用的是 yarn…) brew install yarn

  1. 打来到项目文件夹
  2. 运行下面 添加 webpack2 到全局 和 本地项目.

    yarn global add webpack@2.1.0-beta.25 webpack-dev-server@2.1.0-beta.10 yarn add –dev webpack@2.1.0-beta.25 webpack-dev-server@2.1.0-beta.10

  3. 根目录 新建一个 webpack.config.js 文件用来声明 Webpack 的配置:

    ‘use strict’; const webpack = require(“webpack”); module.exports = { context: __dirname + “/src”, entry: { app: “./app.js”, }, output: { path: __dirname + “/dist”, filename: “[name].bundle.js”, }, };

多个文件一个输出

所有文件会按数组顺序一起打包到 dist/app.bundle.js 一个文件当中。 ‘use strict’;

const webpack = require("webpack");

module.exports = {
  context: __dirname + "/src",
  entry: {
app: ["./home.js", "./events.js", "./vendor.js"],
  },
  output: {
path: __dirname + "/dist",
filename: "[name].bundle.js",
  },
};

多个文件多个输出

打包成三个文件:dist/home.bundle.js、dist/events.bundle.js 和 dist/contact.bundle.js。 const webpack = require(“webpack”);

module.exports = {
  context: __dirname + "/src",
  entry: {
home: "./home.js",
events: "./events.js",
contact: "./contact.js",
  },
  output: {
path: __dirname + "/dist",
filename: "[name].bundle.js",
  },
};

webpack 本地开发

只需要在 webpack.config.js 里添加一个 devServer 对象:

module.exports = {
  context: __dirname + "/src",
  entry: {
app: "./app.js",
  },
  output: {
filename: "[name].bundle.js",
path: __dirname + "/dist/assets",
publicPath: "/assets",            // New
  },
  devServer: {
contentBase: __dirname + "/src",  // New
  },
};

现在新建一个 src/index.html 文件,加入下面这行:

<script src="/assets/app.bundle.js"></script>

然后在命令行中,运行:

webpack-dev-server

服务器现在就运行在了 localhost:8080 上。注意 script 标签中的 /assets 对应的是 output.publicPath的值 - 可以随便填成你想要的命名(如果需要一个 CDN,这就很有用了)。

当你更改 JavaScript 代码的时候,Webpack 就会实时更新页面而无需手动刷新浏览器。但是,任何对webpack.config.js 的更改都需要重启服务器才可以生效。

loaders

目前为止,我们所讲到的都是关于 JavaScript 代码的使用。从 JavaScript 代码开始是非常重要的,因为这是 Webpack 唯一使用的语言。我们可以处理任何文件类型,只要将它们传进 JavaScript 代码中。这个功能用 Loaders 来实现。

一个 loader 可以指向一个像 Sass 的预处理器,或者像 Babel 的编译器。在 NPM 中,它们通常是像 sass-loader或 babel-loader 这样命名为 -loader。

Babel + ES6

如果我们想要在项目中通过 Babel 来使用 ES6,首先要在本地正确地安装一些 loader:

yarn add --dev babel-loader babel-core babel-preset-es2015

…然后把它们添加进 webpack.config.js 好让 Webpack 知道哪里使用它们。

module.exports = {
  // …
  module: {
rules: [
  {
test: /\.js$/,
use: [{
  loader: "babel-loader",
  options: { presets: ["es2015"] }
}],
  },

  // Loaders for other file types can go here
],
  },
  // …
};


这样做就可以为 /\.js$/ 正则表达式寻找以 .js 结尾的文件,最后通过 Babel 编译加载。Webpack 依赖正则表达式给予你完整的控制 - 但它不会限制你的文件后缀,或者假设你的代码必须以某种特定形式组织起来。举个例子:也许你的 /my_legacy_code/ 文件夹里的代码不是用 ES6 写的,那么你就可以把上面的 test 修改为 /^((?!my_legacy_code).)*\.js$/,这样就可以绕过这个文件夹,其余文件用 Babel 编译。

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


module.exports = {
  // …
  module: {
rules: [
  {
test: /\.css$/,
use: ["style-loader", "css-loader"],
  },
  // …
],
  },
};

这些 loader 会以数组逆序运行。这意味着 css-loader 会在 style-loader 之前运行。

从 JS 里加载 CSS 相当爽,因为你可以用一种强有力的新方式去模块化 CSS 代码了。 假设你只通过 button.js 加载了 button.css,这就意味着如果 button.js 没有实际用到的话,它的 CSS 也不会打包进我们的生产构建结果。 如果你坚持使用像 SMACSS 或者 BEM 那样的面向组件的 CSS,就会知道把 CSS 和 HTML + JavaScript 代码放更近的价值了。

Sass

yarn add --dev sass-loader node-sass

然后添加另一条规则:

module.exports = {
  // …
  module: {
rules: [
  {
test: /\.(sass|scss)$/,
use: [
  "style-loader",
  "css-loader",
  "sass-loader",
]
  }
  // …
],
  },
};

接下来当 JavaScript 调用 import 引入一个 .scss 或 .sass 文件时,Webpack 就会做它该做的事情了。

分开打包css

或许你正在处理渐进式增强的网站,又或许因为其他的原因你需要一个分离的 CSS 文件。我们可以简单地实现,只需要在配置里用 extract-text-webpack-plugin 替换掉 style-loader,而无需改变其他任何代码。以 app.js文件为例:

import styles from ‘./assets/stylesheets/application.css’;

本地安装插件(我们需要这个的测试版本,2016年10月发布):

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 的时候就可以看到一个 app.bundle.css 文件出现在 output 目录里了。像往常一样简单地添加一个 <link> 标签到 HTML 文件里就可以了。

webpack 思考方式

为了最大程度发挥 Webpack 的作用,你不得不从模块的角度去思考(小、可复用、自包含进程),一件件事情慢慢去做好。这意味着下面这样的东西

└── js/
└── application.js   // 300KB of spaghetti code

一起的js 变成下面的js

└── js/
├── components/
│   ├── button.js
│   ├── calendar.js
│   ├── comment.js
│   ├── modal.js
│   ├── tab.js
│   ├── timer.js
│   ├── video.js
│   └── wysiwyg.js
│
└── application.js  // ~ 1KB of code; imports from ./components/

结果是干净且可复用的代码。每个独立的组件取决于导入自身的依赖,并按照它想要的方式导出到其他模块。配合 Babel + ES6 使用,还可以利用 JavaScript Classes 做出更好的模块化,并且不要去想它,作用域只是在起作用。

模块加载器 & 打包工具.

能把各种资源(js, coffee, css,less,sass, 图片) 等等都作为模块来使用和处理.

直接使用 require(xxx) 来引入模块. 即使某些需要经过编译(sass等)才能用.也不用太费心思.

主流项目 都是 基于 webpack 开发啊.

webpack 优势

使用 commonJS 格式来写脚本. 扩展性能强.

配置示例

var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');

module.exports = {
//插件项
plugins: [commonsPlugin],
//页面入口文件配置
entry: {
index : './src/js/page/index.js'
},
//入口文件输出配置
output: {
path: 'dist/js/page',
filename: '[name].js'
},
module: {
//加载器配置
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
]
},
//其它解决方案配置
resolve: {
root: 'E:/github/flux-example/src', //绝对路径
extensions: ['', '.js', '.json', '.scss'],
alias: {
AppStore : 'js/stores/AppStores.js',
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}
};

一: plugins: 插件.

后面是插件名字.

二: entry output

entry: 页面入口文件配置. output: 输出配置

也就是 入口文件最终要生成什么名字的文件. 存放在哪里.

entry output 语法:
{
entry: {
page1: "./page1",
//支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出
page2: ["./entry1", "./entry2"]
},
output: {
path: "dist/js/page",
filename: "[name].bundle.js"
}
}

该段代码最终会生成一个 page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下。

三: module.loaders

最关键的配置. 告诉webpack 每种文件都用什么加载器来处理.

module: {
//加载器配置
loaders: [
//.css 文件使用 style-loader 和 css-loader 来处理
{ test: /\.css$/, loader: 'style-loader!css-loader' },
//.js 文件使用 jsx-loader 来编译处理
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
//.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
//图片文件使用 url-loader 来处理,小于8kb的直接转为base64
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
]
}

注意所有的加载器都需要通过 npm 来加载,并建议查阅它们对应的 readme 来看看如何使用。 拿最后一个 url-loader 来说,它会将样式中引用到的图片转为模块来处理,使用该加载器需要先进行安装: npm install url-loader -save-dev 配置信息的参数“?limit=8192”表示将所有小于8kb的图片都转为base64形式(其实应该说超过8kb的才使用 url-loader 来映射到文件,否则转为data url形式)。

四: resolve 配置

resolve: {
//查找module的话从这里开始查找
root: 'E:/github/flux-example/src', //绝对路径
//自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
extensions: ['', '.js', '.json', '.scss'],
//模块别名定义,方便后续直接引用别名,无须多写长长的地址
alias: {
AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}

运行 webpack

$ webpack --display-error-details

后面的参数“–display-error-details”是推荐加上的, 方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。

webpack 参数 $ webpack –config XXX.js //使用另一份配置文件(比如webpack.config2.js)来打包

$ webpack --watch   //监听变动并自动打包

$ webpack -p    //压缩混淆脚本,这个非常非常重要!

$ webpack -d    //生成map映射文件,告知哪些模块被最终打包到哪里了

其中的 -p 是很重要的参数,曾经一个未压缩的 700kb 的文件,压缩后直接降到 180kb(主要是样式这块一句就独占一行脚本,导致未压缩脚本变得很大)。

模块引入

HTML 模块引入

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>demo</title>
</head>
<body>
  <script src="dist/js/page/common.js"></script>
  <script src="dist/js/page/index.js"></script>
</body>
</html>

body 最后的 js 直接写 webpack 最终生成的文件就可以了. CSS 都不用写!! 因为帮你直接内建到 成html内联样式了..

JS 模块引入

直接使用 commonJS 来写. 还可以引入未编译的模块 如 sass. coffee. (只要你在 webpack.config.js 里配置好了对应的加载器)

页面入口文件(index.js) require(‘../../css/reset.scss’); //加载初始化样式 require(‘../../css/allComponent.scss’); //加载组件样式 var React = require(‘react’); var AppWrap = require(‘../component/AppWrap’); //加载组件 var createRedux = require(‘redux’).createRedux; var Provider = require(‘redux/react’).Provider; var stores = require(‘AppStore’);

var redux = createRedux(stores);

var App = React.createClass({
render: function() {
return (
<Provider redux={redux}>
{function() { return <AppWrap />; }}
</Provider>
);
}
});

React.render(
<App />, document.body
);

安装和配置

一: 全局安装

  1. 安装 webpack 全局环境 : npm install webpack -g
  2. 查看 webpack 版本: webpack -v

    webpack 是 node 项目. 确保电脑有安装 node.js & npm

二: 项目安装

  1. 终端进入项目路径
  2. 确保有 package.json (没有就 npm init 一路回车来创建.) 终端进入到项目文件夹. → npm init // 就是创建/修改 package.json 的命令. 不会影响别的文件 → name: (cms) // 回车.会显示当前文件夹的名字. → version: (1.0.0) // 回车.. → description: // 回车 (让你添加描述的…) → entry point: (highlight.js) // 回车 后面可以改的…. → ….. // 一路回车!!!!

  3. 安装 webpack 依赖 npm install webpack –save-dev

     // 下面是上面命令的缩写( 选一个就行.)
     // -save :     模块名将被添加到dependencies.    可以简化成参数 -S
     // -save-dev:  模块名将被添加到devDependencies,可以简化为参数 -D
     npm i webpack -D
    

创建一个简单的包进入点

新建文件: index.js: 文件内容: `console.log(“xu.jian”); `

. 运行方法1: 用node直接运行脚本

$node index.js   
xu.jian 

运行方法2: 用 require 在其他地方引用脚本

  • 首先进入 node的交互界面: (终端: 输入 node, 然后按回车就进去了)
  • 输入 require('./index') 然后回车

  • 实例代码: ➜ cms git:(master) ✗ node index.js hello xu.jian ➜ cms git:(master) ✗ node

    require(“/index”) Error: Cannot find module ‘/index’ at Function.Module._resolveFilename (module.js:470:15) at Function.Module._load (module.js:418:25) at Module.require (module.js:498:17) at require (internal/module.js:20:19) at repl:1:1 at realRunInThisContextScript (vm.js:22:35) at sigintHandlersWrap (vm.js:98:12) at ContextifyScript.Script.runInThisContext (vm.js:24:12) at REPLServer.defaultEval (repl.js:313:29) at bound (domain.js:280:14) require(“./index”) hello xu.jian {} require(“./index”) {} require(“./”) {}

  • 实例解析: 这里 最后的 {} 是require的返回值. node 允许我们省略.js 扩展名. 因为运行的就是js.. 如果我们这这个交互界面中 继续运行 require(“./index”) 我们将得到相同的返回值但是不会得到console.log输出, 因为require不会再同一个脚本中运行两次. ./ 是当前文件夹的意思. 非常重要. 点必须有.

下面回到 package.json “main”: “index.js” 当你 require 一个含有package.json 文件的文件夹时候. node 会默认你require package.json 里的 main 参数后面的文件.

require(“./index”) {} 两者等价 require(‘./’) {}

第一个npm模块: colors

让你的 node.js console 带上颜色.

突然npm命令没有了 折腾半天才发现 要用cnpm… Warning: node-7.5.0 already installed, it’s just not linked.

终端cs项目文件夹(直接运行就行): $ cnpm install –save colors 然后去看 package.json dependencies 下面应该多了个 “colors”: “0.6.0-1” 这个就是 –save 的作用.

colors 模块使用方法

要引入的… 不是你输入任何东西都会自动高亮的. var colors = require(‘colors’);

console.log('hello'.green); // outputs green text
console.log('i like cake and pies'.underline.red) // outputs red underlined text
console.log('inverse the color'.inverse); // inverses the color
console.log('OMG Rainbows!'.rainbow); // rainbow
console.log('Run the trap'.trap); // Drops the bass

使用实例(这里颜色没显示处理.去终端肯定有颜色的.) ➜ cms git:(master) ✗ node

var colors = require(‘colors’); undefined console.log(‘hello’.green); hello undefined console.log(colors.red.underline(‘i like cake and pies’)) i like cake and pies undefined console.log(colors.inverse(‘inverse the color’)) inverse the color undefined console.log(colors.rainbow(‘OMG Rainbows!’)); OMG Rainbows! undefined console.log(colors.trap(‘Run the trap’)); ЯՍÑ ͳԊƎ ŦȐȺҎ undefined

重写 index.js (进一步了解依赖模块)

  1. 把 index.js 内容替换成下面的. var colors = require(‘colors’); console.log(‘Hello,’.red, ‘npm!’.green);

  2. 终端用 node 运行 index.js 输出的 hellp npn 在终端里就会变成多彩的.只是博客里没颜色而已. ➜ cms git:(master) ✗ node index.js Hello, npm!

node_modules 的层级 require 怎么知道去哪找 colorss.js 模块呢. node 首先查找本地项目下的 node_modules文件夹(隐藏的). 使用 npm install 安装任意包的时候被自动创建. 如果本地项目没有 colors.js 那就会查找上一级的. 没有再查找上一级的 .知道系统的根目录..

npm收尾工作 如果我要和全世界分析 hello-npm 项目. 我会push到 github .再npm registry 中发布我的包. 由于全世界只能有一个叫 npm-hello的包. 你要注册一个账户..然后改个包名字. 就可以了…

发布好之后 就可以用下面命令来安装了: $npm install hello-npm

到这里环境就安装好了. package.json里也有了 webpack

第一个 webpack 打包程序

创建一个静态页面: index.html 创建一个 js 入口文件: entry.js 名字随意. 打包的时候 对应就可以.

index.html <html> <head> </head> <body> <h1 id="app"></h1> </body> </html>

entry.js document.getElementById(‘app’).innerHTML=”这是我第一个打包成功的程序”;

然后 执行 webpack entry.js bundle.js

//就个 必须在 本地搭建的html中执行. // 博客文件夹中执行会报错.. 不知为啥, 我用的是 MAMP Pro. 搭建环境很方便. ➜ webpack webpack entry.js bundle.js Hash: fa8c4054e08d59170d93 Version: webpack 2.2.1 Time: 70ms Asset Size Chunks Chunk Names bundle.js 2.57 kB 0 [emitted] main [0] ./entry.js 58 bytes {0} [built] ➜ webpack

本来 html 是空白的. 现在就出来一行字.这是我第一个打包成功的程序 因为 webpack 执行了 js . 把js结果放到html里了.

增加一个文件打包

  1. 新建first.js var h2= document.createElement(“h2”) h2.innerHTML=”不是吧,那么快第二个打包程序啦!”; document.body.appendChild(h2);

  2. 更改 entry.js document.getElementById(‘app’).innerHTML=”这是我第一个打包成功的程序”; //添加 require(“./first.js”);

  3. 运行打包程序: webpack entry.js bundle.js

  4. 下面就可以看出 第一次 第二次的区别了 ➜ webpack webpack entry.js bundle.js Hash: fa8c4054e08d59170d93 Version: webpack 2.2.1 Time: 70ms Asset Size Chunks Chunk Names bundle.js 2.57 kB 0 [emitted] main [0] ./entry.js 58 bytes {0} [built] ➜ webpack webpack entry.js bundle.js Hash: 3bf753e1b1028677c85b Version: webpack 2.2.1 Time: 78ms Asset Size Chunks Chunk Names bundle.js 2.77 kB 0 [emitted] main [0] ./first.js 100 bytes {0} [built] [1] ./entry.js 83 bytes {0} [built] ➜ webpack

webpack 会分析入口文件. 解析包含依赖关系的各个文件. 这些文件(模块)都打包到 bundle.js 中. webpack 会给每个模块发配一个唯一的id. 并通过这个id索引和访问模块 先执行 entry.js 中的代码. 其他模块会在运行 require 的时候再执行.

webpack 二

上面打包了 js 文件. 其实通过loader 还可以处理其他类型的文件.

Loader 介绍

loader 可以理解成 模块和资源的转换器. 本身是一个函数. 接受源文件作为参数. 返回转换的结果. 这样可以通过require来加载任何类型的模块或者文件.

loader 特性

Loader可以通过管道方式链式调用,每个loader可以把资源转换成任意格式并传递给下一个loader,但是最后一个loader必须返回JavaScript。 Loader可以同步或异步执行。 Loader运行在node.js环境中,所以可以做任何可能的事情。 Loader可以接受参数,以此来传递配置项给loader。 Loader可以通过文件扩展名(或正则表达式)绑定给不同类型的文件。 Loader可以通过npm发布和安装。 除了通过package.json的main指定,通常的模块也可以导出一个loader来使用。 Loader可以访问配置。 插件可以让loader拥有更多特性。 Loader可以分发出附加的任意文件。

loader 安装

先安装读取 css 文件的 css-loader. 再用 style-loader 把它插入到页面中.

扩展名自动绑定 loader

如果每次 require css 都要写个 !style!css!前缀 很麻烦的啊. 我们需要webpack 根据文件的后缀名来自动绑定前缀.

来看看更简便的方式,将 entry.js 中的 require(“!style!css!./style.css”)修改为require(“./style.css”),可以改变一个背景颜色让你更明显的查看到变化!然后执行:

webpack entry.js bundle.js --module-bind "css=style!css"

没成功对吧! 因为!在命令行中具有特殊的含义,所以我们需要对它进行转义操作。再来试试:

webpack ./entry.js bundle.js --module-bind "css=style\!css"

成功的话,应该能再次看到背景的变化。 虽然这样可以将多个css文件进行编译打包,但是总感觉很是繁琐,我不想每次都运行那么一长串的命令怎么办?继续向下走吧。

jekyll webpack js

  1. 项目目录先安装 webpack npm install webpack -g
  2. 梳理项目结构 :
  3. 文件结构没要求. webpack 配置文件 .只要有 entry 和 output 文件夹就可以.

默认文件结构 . ├── _config.yml ├── _includes │ ├── … ├── _layouts │ ├── default.html │ ├── page.html │ └── post.html ├── _posts │ ├── … ├── _sass │ ├── _base.scss │ ├── _layout.scss │ └── _syntax-highlighting.scss ├── about.md ├── css │ └── main.scss ├── feed.xml └── index.html

成品文件结构:

  • 根目录 有 package.json 和 webpack.config.js
  • 多了个 src 目录. … (source: src)
  • 多了个 public 文件夹… (config : destination: public )
  • 多了个 webpack 文件夹. 里面含有 entry.js

      .
      ├── _config.yml
      ├── package.json
      ├── public
      │ ├── …
      ├── src
      │ ├── _includes
      │ │ ├── …
      │ ├── _layouts
      │ │ ├── default.html
      │ │ ├── page.html
      │ │ └── post.html
      │ ├── _posts
      │ │ ├── …
      │ ├── _sass
      │ │ ├── …
      │ ├── about.md
      │ ├── assets
      │ │ ├── css
      │ │ ├── images
      │ │ └── javascripts
      │ │ └── bundle.js
      │ ├── feed.xml
      │ └── index.html
      ├── webpack
      │ ├── entry.js
      │ └── components
      │ └── …
      └── webpack.config.js
    

    这个需要 你要移动 所有 jekyll build 需要的文件移动到 src 目录. 这里由于你把 本地是根目录site文件夹下生成的. 改成了public. 所以你要 用 pow 这个工具来查看效果. pow 软件作用以后再说.简单 的 环境搭建???

  1. 添加 package.json. 没有这个文件 npm 就不知道要运行什么. 也就是npm的配置文件吧.

  2. 添加 webpack 文件夹
  3. webpack 文件夹下 添加 entry.js
  4. 移除里javascripts 文件夹里的所有文件(先到电脑别的地方).保留这个文件夹.
  5. 配置 webpack.config.js module.exports = { // webpack folder’s entry js — excluded from jekll’s build process. entry: ‘./webpack/entry.js’, output: { // we’re going to put the generated file in the assets folder so jekyll will grab it. path: ‘src/assets/javascripts/’, filename: ‘bundle.js’ }, module: { loaders: [ { test: /.jsx?$/, exclude: /(node_modules)/, loader: ‘babel’, // ‘babel-loader’ is also a legal name to reference query: { presets: [‘react’, ‘es2015’] } } ] } };

这个配置文件告诉webpack. 哪里去找入口文件: entry.js 把生成的文件 改成什么名字 .输出到哪个文件夹.

  1. 忽略文件

你必须要 告诉 github 和jekyll 忽略下面的文件夹: node_modules 下的所有文件. 这个很多很多很多文件…. 在 gitignore 里 添加 /src/assets/bundle.js public 和 node.modules 文件夹.

  1. 把 bundle.js 添加到 html 就可以了.

  2. 安装 依赖.

  3. entry.js 放一点内容.可以有输出
  4. build
  5. 下面就是 react了..

总结: 只要把 entry.js 和 first.js 输出成一个. bundle.js 就可以了.

只要修改下 webpack 指定enrtry 入口. 和输出文件夹.输出名字 再引入到 html 就可以了.

doit.

  1. 配置

每个项目下都必须有一个配置文件: webpack.config.js 告诉webpack 需要做什么.

安装

第一步

使用 yarn 来替代 npm (两个功能一样 但是教程用的是 yarn…) brew install yarn

  1. 打来到项目文件夹
  2. 运行下面 添加 webpack2 到全局 和 本地项目.

    yarn global add webpack@2.1.0-beta.25 webpack-dev-server@2.1.0-beta.10 yarn add –dev webpack@2.1.0-beta.25 webpack-dev-server@2.1.0-beta.10

  3. 根目录 新建一个 webpack.config.js 文件用来声明 Webpack 的配置:

    ‘use strict’; const webpack = require(“webpack”); module.exports = { context: __dirname + “/src”, entry: { app: “./app.js”, }, output: { path: __dirname + “/dist”, filename: “[name].bundle.js”, }, };

多个文件一个输出

所有文件会按数组顺序一起打包到 dist/app.bundle.js 一个文件当中。 ‘use strict’;

const webpack = require("webpack");

module.exports = {
  context: __dirname + "/src",
  entry: {
app: ["./home.js", "./events.js", "./vendor.js"],
  },
  output: {
path: __dirname + "/dist",
filename: "[name].bundle.js",
  },
};

多个文件多个输出

打包成三个文件:dist/home.bundle.js、dist/events.bundle.js 和 dist/contact.bundle.js。 const webpack = require(“webpack”);

module.exports = {
  context: __dirname + "/src",
  entry: {
home: "./home.js",
events: "./events.js",
contact: "./contact.js",
  },
  output: {
path: __dirname + "/dist",
filename: "[name].bundle.js",
  },
};

webpack 本地开发

只需要在 webpack.config.js 里添加一个 devServer 对象:

module.exports = {
  context: __dirname + "/src",
  entry: {
app: "./app.js",
  },
  output: {
filename: "[name].bundle.js",
path: __dirname + "/dist/assets",
publicPath: "/assets",            // New
  },
  devServer: {
contentBase: __dirname + "/src",  // New
  },
};

现在新建一个 src/index.html 文件,加入下面这行:

<script src="/assets/app.bundle.js"></script>

然后在命令行中,运行:

webpack-dev-server

服务器现在就运行在了 localhost:8080 上。注意 script 标签中的 /assets 对应的是 output.publicPath的值 - 可以随便填成你想要的命名(如果需要一个 CDN,这就很有用了)。

当你更改 JavaScript 代码的时候,Webpack 就会实时更新页面而无需手动刷新浏览器。但是,任何对webpack.config.js 的更改都需要重启服务器才可以生效。

loaders

目前为止,我们所讲到的都是关于 JavaScript 代码的使用。从 JavaScript 代码开始是非常重要的,因为这是 Webpack 唯一使用的语言。我们可以处理任何文件类型,只要将它们传进 JavaScript 代码中。这个功能用 Loaders 来实现。

一个 loader 可以指向一个像 Sass 的预处理器,或者像 Babel 的编译器。在 NPM 中,它们通常是像 sass-loader或 babel-loader 这样命名为 -loader。

Babel + ES6

如果我们想要在项目中通过 Babel 来使用 ES6,首先要在本地正确地安装一些 loader:

yarn add --dev babel-loader babel-core babel-preset-es2015

…然后把它们添加进 webpack.config.js 好让 Webpack 知道哪里使用它们。

module.exports = {
  // …
  module: {
rules: [
  {
test: /\.js$/,
use: [{
  loader: "babel-loader",
  options: { presets: ["es2015"] }
}],
  },

  // Loaders for other file types can go here
],
  },
  // …
};


这样做就可以为 /\.js$/ 正则表达式寻找以 .js 结尾的文件,最后通过 Babel 编译加载。Webpack 依赖正则表达式给予你完整的控制 - 但它不会限制你的文件后缀,或者假设你的代码必须以某种特定形式组织起来。举个例子:也许你的 /my_legacy_code/ 文件夹里的代码不是用 ES6 写的,那么你就可以把上面的 test 修改为 /^((?!my_legacy_code).)*\.js$/,这样就可以绕过这个文件夹,其余文件用 Babel 编译。

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


module.exports = {
  // …
  module: {
rules: [
  {
test: /\.css$/,
use: ["style-loader", "css-loader"],
  },
  // …
],
  },
};

这些 loader 会以数组逆序运行。这意味着 css-loader 会在 style-loader 之前运行。

从 JS 里加载 CSS 相当爽,因为你可以用一种强有力的新方式去模块化 CSS 代码了。 假设你只通过 button.js 加载了 button.css,这就意味着如果 button.js 没有实际用到的话,它的 CSS 也不会打包进我们的生产构建结果。 如果你坚持使用像 SMACSS 或者 BEM 那样的面向组件的 CSS,就会知道把 CSS 和 HTML + JavaScript 代码放更近的价值了。

分开打包css

或许你正在处理渐进式增强的网站,又或许因为其他的原因你需要一个分离的 CSS 文件。我们可以简单地实现,只需要在配置里用 extract-text-webpack-plugin 替换掉 style-loader,而无需改变其他任何代码。以 app.js文件为例:

import styles from ‘./assets/stylesheets/application.css’;

本地安装插件(我们需要这个的测试版本,2016年10月发布):

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 的时候就可以看到一个 app.bundle.css 文件出现在 output 目录里了。像往常一样简单地添加一个 <link> 标签到 HTML 文件里就可以了。

webpack 思考方式

为了最大程度发挥 Webpack 的作用,你不得不从模块的角度去思考(小、可复用、自包含进程),一件件事情慢慢去做好。这意味着下面这样的东西

└── js/
└── application.js   // 300KB of spaghetti code

一起的js 变成下面的js

└── js/
├── components/
│   ├── button.js
│   ├── calendar.js
│   ├── comment.js
│   ├── modal.js
│   ├── tab.js
│   ├── timer.js
│   ├── video.js
│   └── wysiwyg.js
│
└── application.js  // ~ 1KB of code; imports from ./components/

结果是干净且可复用的代码。每个独立的组件取决于导入自身的依赖,并按照它想要的方式导出到其他模块。配合 Babel + ES6 使用,还可以利用 JavaScript Classes 做出更好的模块化,并且不要去想它,作用域只是在起作用。

模块加载器 & 打包工具.

能把各种资源(js, coffee, css,less,sass, 图片) 等等都作为模块来使用和处理.

直接使用 require(xxx) 来引入模块. 即使某些需要经过编译(sass等)才能用.也不用太费心思.

主流项目 都是 基于 webpack 开发啊.

webpack 优势

使用 commonJS 格式来写脚本. 扩展性能强.

配置示例

var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');

module.exports = {
//插件项
plugins: [commonsPlugin],
//页面入口文件配置
entry: {
index : './src/js/page/index.js'
},
//入口文件输出配置
output: {
path: 'dist/js/page',
filename: '[name].js'
},
module: {
//加载器配置
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
]
},
//其它解决方案配置
resolve: {
root: 'E:/github/flux-example/src', //绝对路径
extensions: ['', '.js', '.json', '.scss'],
alias: {
AppStore : 'js/stores/AppStores.js',
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}
};

一: plugins: 插件.

后面是插件名字.

二: entry output

entry: 页面入口文件配置. output: 输出配置

也就是 入口文件最终要生成什么名字的文件. 存放在哪里.

entry output 语法:
{
entry: {
page1: "./page1",
//支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出
page2: ["./entry1", "./entry2"]
},
output: {
path: "dist/js/page",
filename: "[name].bundle.js"
}
}

该段代码最终会生成一个 page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下。

三: module.loaders

最关键的配置. 告诉webpack 每种文件都用什么加载器来处理.

module: {
//加载器配置
loaders: [
//.css 文件使用 style-loader 和 css-loader 来处理
{ test: /\.css$/, loader: 'style-loader!css-loader' },
//.js 文件使用 jsx-loader 来编译处理
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
//.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
//图片文件使用 url-loader 来处理,小于8kb的直接转为base64
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
]
}

注意所有的加载器都需要通过 npm 来加载,并建议查阅它们对应的 readme 来看看如何使用。 拿最后一个 url-loader 来说,它会将样式中引用到的图片转为模块来处理,使用该加载器需要先进行安装: npm install url-loader -save-dev 配置信息的参数“?limit=8192”表示将所有小于8kb的图片都转为base64形式(其实应该说超过8kb的才使用 url-loader 来映射到文件,否则转为data url形式)。

四: resolve 配置

resolve: {
//查找module的话从这里开始查找
root: 'E:/github/flux-example/src', //绝对路径
//自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
extensions: ['', '.js', '.json', '.scss'],
//模块别名定义,方便后续直接引用别名,无须多写长长的地址
alias: {
AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}

运行 webpack

$ webpack --display-error-details

后面的参数“–display-error-details”是推荐加上的, 方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。

webpack 参数 $ webpack –config XXX.js //使用另一份配置文件(比如webpack.config2.js)来打包

$ webpack --watch   //监听变动并自动打包

$ webpack -p    //压缩混淆脚本,这个非常非常重要!

$ webpack -d    //生成map映射文件,告知哪些模块被最终打包到哪里了

其中的 -p 是很重要的参数,曾经一个未压缩的 700kb 的文件,压缩后直接降到 180kb(主要是样式这块一句就独占一行脚本,导致未压缩脚本变得很大)。

模块引入

HTML 模块引入

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>demo</title>
</head>
<body>
  <script src="dist/js/page/common.js"></script>
  <script src="dist/js/page/index.js"></script>
</body>
</html>

body 最后的 js 直接写 webpack 最终生成的文件就可以了. CSS 都不用写!! 因为帮你直接内建到 成html内联样式了..

JS 模块引入

直接使用 commonJS 来写. 还可以引入未编译的模块 如 sass. coffee. (只要你在 webpack.config.js 里配置好了对应的加载器)

页面入口文件(index.js) require(‘../../css/reset.scss’); //加载初始化样式 require(‘../../css/allComponent.scss’); //加载组件样式 var React = require(‘react’); var AppWrap = require(‘../component/AppWrap’); //加载组件 var createRedux = require(‘redux’).createRedux; var Provider = require(‘redux/react’).Provider; var stores = require(‘AppStore’);

var redux = createRedux(stores);

var App = React.createClass({
render: function() {
return (
<Provider redux={redux}>
{function() { return <AppWrap />; }}
</Provider>
);
}
});

React.render(
<App />, document.body
);