Skip to content

教你一步步从零构建webpack开发多页面环境 #27

@riskers

Description

@riskers


使用 webpack 已经将近一年了,期间用它构建过4、5个项目,踩过一些坑,现在用自己的理解记录下来。

我现在教你如何一步一步搭建 webpack 开发的多页面项目。本文项目地址在 https://github.com/riskers/generate-pages-tutorial

首先需要安装:

git clone https://github.com/riskers/generate-pages-tutorial

这里使用的是 webpack 1.x,webpack 2 见文末

注意每一步的 webpack.config.jspageage.json

一、基本 JavaScript 模块的处理

cd 1_multi_pages
npm install
npm run build

查看 webpack.config.js 可以其实就是配置多个 entry 而已,可以看到 dist 下生成编译好的文件:

|--- dist
        |--- page1
                |--- main.js
        |--- page2
                |--- main.js

这里的目录层级和 entry 中的模块名(page1/mainpage2/main)对应。

打开 page1.htmlpage2.html 就可以看到我们的js模块生效了。现在进入下一步!

二、CSS 模块的处理

通过上一步,我们已经解决了 JavaScript 模块的问题,而页面中还有 CSS 。webpack 默认是只处理 JavaScript 的,所以我们要引入 css-loaderstyle-loader 来处理 CSS。

cd 2_css
npm install
npm run build

CSS

{
    test: /\.css$/,
    loaders: ['style', 'css']
}

loader 是专门处理某些模块的处理器。webpack 只能处理 js ,为了能够处理 CSS ,就需要 css-loader;而为了能够在页面中插入 CSS ,还需要 style-loader

打开 page1.html 就可以看到 css 生效了。

less

{
    test: /\.less$/,
    loaders: ['style', 'css', 'less']
}

如果使用的是 less ,就需要安装 lessless-loader

打开 page2.html 就可以看到 less 生效了。

sass

{
    test: /\.scss$/,
    loaders: ['style', 'css', 'sass']
}

如果使用的是 sass ,就需要安装 node-sasssass-loader

打开 page3.html 就可以看到 less 生效了。

postcss

module: {
    loaders: [
        {
            test: /\.css$/,
            include: ROOT + '/src/page4',
            loaders: ['style', 'css', 'postcss']
        }
    ]
},
postcss: function() {
    return [autoprefixer]
}

如果使用的是 sass ,就需要安装 postcss-loader,这里是以 autoprefixer 为例。

打开 page4.html 就可以看到 less 生效了。

生成 CSS 文件

以上方法都是用 JS 生成 CSS,但是实际上,我们需要的是 CSS 文件,可以使用 extract-text-webpack-plugin 来解决。

打开 page5.html 可以看到效果

三、reload

上面2节我们已经掌握 JS 模块和 CSS 模块的处理,并且能够让 CSS 独立生成文件了,现在我们觉得每次修改代码然后 build 再刷新浏览器这个过程实在太慢了,而且也没必要每修改一行代码,就生成新文件,这是构建速度慢的主要原因。

webpack-dev-server 是 webpack 自带的一个开发服务器,支持热替换、代理等等功能。

cd 3_reload
npm install
npm run dev

打开 0.0.0.0:8888/page1.html ,你就可以看到页面了。而且无论你修改 main.jsstyle.csstpl/page1.html 都会让浏览器自动刷新。

这里使用了:

  • html-webpack-plugin: 在页面中自动注入 js 和 css
  • html-webpack-harddisk-plugin: 每次修改 pages/tpl 内文件时,会自动在 pages/html 内生成对应的文件
  • raw-loader: 可以 require html 文件,做到每修改一次 tpl 文件,浏览器自动刷新一次页面

还有一点值得注意,因为 reload 功能是开发时才需要的,所以我们在 build 的时候要把这部分剔除,cross-envDefinePlugin 的配合可以做到这点。

  • cross-env 能够不分系统地在全局注入变量,下面这条命令就是将 DEV 注入 ENV 环境变量
cross-env ENV=DEV webpack-dev-server --inline --hot --quiet --progress --content-base pages/html  --host 0.0.0.0 --port 8888
  • DefinePlugin 将 process.env.ENV 这个环境变量注入 ENV
new webpack.DefinePlugin({
    'ENV': JSON.stringify(process.env.ENV)
})
  • main.js 中就可以区分是开发环境还是生产环境了:
if(ENV == 'DEV') {
    require('pages/html/page1.html')    
}

四、ES2015 && babel

如果你要在 webpack 中配置 ES2015 的开发环境,需要 babel 的帮助:

  • babel-core
  • babel-loader
  • babel-preset-es2015
  • babel-preset-stage-0
  • babel-plugin-add-module-exports
  • babel-plugin-transform-runtime
cd 4_es2015
npm install
npm run dev

然后在 webpack.config.js 中:

{
    test: /\.js$/,
    loader: "babel",
    exclude: /node_modules/
}

注意 exclude: /node_modules/ 很重要,否则 babel 可能会把 node_modules 中所有模块都用 babel 编译一遍!

并且,在根目录下新建 .babelrc

{
    presets: [
        "es2015",
        "stage-0"
    ],
    plugins: [
        "transform-runtime",
        "add-module-exports"
    ]   
}

然后我们就可以写我们可爱的 ES2015 了:

import './style.css'
import { log } from '../common/index.js'

五、引入库

cd 5_library
npm install
npm run dev

CommonsChunkPlugin

CommonsChunkPlugin 是 webpack 自带的插件,能够把公有模块提取出来:

plugins: [
    new webpack.optimize.CommonsChunkPlugin('common','common.js') 
]

HtmlWebpackPlugin 中加入 common/index.js 模块,我们就可以看到 common/index.js 模块被提取到了 common.js 中。否则的话,page1/mainpage2/main 中都会打包 common/index.js

externals

实际开发中,我们还会在页面使用 <script> 引入一些常用库,比如 jQuery ,那么我们需要

// 当在 js 中 require jQuery 时,实际上是指向 `window.jQuery`
externals: {
    jQuery: 'window.jQuery'
}

然后我们就可以在 page1/main.js 中使用 jQuery 了:

import $ from 'jQuery'
$('body')
    .append('<p>this is jQuery render</p>')
    .css('color', '#FFF')

ProvidePlugin

当然,对于 jQuery 这种每个页面都会使用到的库来说,每次都要 import $ from 'jQuery' 显得很不优雅。可以这样配置:

plugins: [
    new webpack.ProvidePlugin({
        $: 'jquery'
    })
]

这样就可以像 page2/main.js 中那样了:

$('body')
    .append('<p>this is jQuery render</p>')
    .css('color', '#3f3f3f')

六、代理

经过上面几个步骤,我们基本上已经完成了 webpack 的开发环境搭建,但是 pages 里全是静态页面,而我们后端实际上使用的可能是 PHP、Python 甚至是 Node 渲染的动态页面。

现在我们要解决的问题是把现有的 webpack 开发环境和已有的后端环境结合起来,我们这里使用的是 webpack-dev-serverproxy 功能:

devServer: {
    proxy: {
        '*': {
            target: 'http://localhost:8000'
        }
    }
}
cd 6_proxy
npm install
npm run dev

为了模拟一个后端环境,这里使用 PHP 自带的 server 在 8000 端口开启服务:

php -S 127.0.0.1:8000 -t ./pages/html

然后打开 http://0.0.0.0:8888/page1.php 就可以看到页面被 webpack-dev-server 代理过来了。你可以在 pages/html 下得到正式的已经配置好资源路径的页面。

执行 npm run build 后,你会在 pages/html 下得到相应 CDN 地址的资源路径,CDN 地址可以在 npm scripts 下配置:

"scripts": {
    "build": "cross-env CDN=http://cdn.a.com webpack"
}

七、团队协作

到此为止,一个 webpack 搭建的多页面开发环境已经完成了,还有一些与 webpack 无关的话题要注意一下。

ESLint

ESLint 是代码检查工具,这里不多介绍了。如果你使用的是 es2015 ,记得安装 babel-eslint 就好。

pre-commit

pre-commit 是一个很好用的工具,你可以使用它强制性地让团队成员在 commit 代码前执行任何命令(ESLint、测试等等)

"scripts": {
    "lint": "eslint app/src/ app/stylesheets"
},
"precommit": [ "lint" ]

注意使用时要先安装:

node node_modules/pre-commit/install.js

八、一个脚手架模板

我还建立了项目 https://github.com/riskers/generate-pages ,它包括了最最基本的 webpack 开发多页面骨架,感兴趣的也可以看看。由其是 map.js 和 模板文件的映射,这种思路应该可以帮你少写很多代码。

最重要的是,赶紧动手开始使用 webpack 吧!

希望这份教程帮到了你 -_-

20170215 更新

最近,webpack 2 终于正式发布了,之前大概看过他的 beta 版本,但是没有正式发布之前我始终没有去实践,这两天得空把 https://github.com/riskers/generate-pages-tutorial 上的代码更新到了 v2 版本。总体来说,webpack2 默认支持 module、提供 tree shaking 是2个比较让我在意的新功能,其他的以后再细细研究了。


向我捐助 | 关于我 | 工作机会


Metadata

Metadata

Assignees

No one assigned

    Labels

    FEweb 前端

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions