前端webpack构建react系列一:开端,让webpack跑起来

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kiramario/article/details/79602732

使用打包技术

什么是webpack打包,我简单地理解为将其他一系列语法(react,JSX,ES6)重新构建成JS。为什么这么做?是因为前端发展到模块化概念,状态驱动概念,有了更新的标准,但这些优秀的概念并没有被标准化,打包就是为了翻译这些新语法使其适应于当前标准,可以理解为JS的浏览器兼容性问题(大家回忆一下这个:客户死活不愿意用google浏览器之IE浏览器兼容性)。

环境介绍
win10
nodejs 8.9.3LTS
npm 5.51 (nodejs自带)

一个开端

依赖包
webpack 3.10.0(全局和本地安装)

1、创建你的项目目录,我是在桌面创建了一个文件夹envtest,然后在此文件夹里面打开powershell(cmd),npm init:这个命令用于创建一个package.json。

2、npm install webpack --save-dev; npm install webpack -g 全局和本地下载webpack,全局下载webpack是为了在cmd命令工具里面可以用webpack命令,这个命令就是构建命令。本地安装是为了可以在项目里面引用。

由于外网太慢了,所以使用淘宝镜像 :
npm –registry https://registry.npm.taobao.org install [package] –save-dev
此方法是临时使用,并不改变npm的registry配置。
另外一种方法是在nodejs安装目录->node_modules->npm->npmrc文件,打开后换行添加registry = https://registry.npm.taobao.org。重新打开cmd命令窗口,输入npm get registry查看当前设置

3、 在根目录下建立webpack.config.js ,这个是webpack构建项目默认配置文件,也可以指定别的配置文件,比如webpack.dist.config.js,不过运行的时候需要假设config参数,webpack --config webpack.dist.config.js.

4、配置webpack.config.js:

var webpack = require('webpack');
module.exports = {
    entry: {
        bundle: './index.js' (1)
    },
    output: {
        path: __dirname + '/build/',  (2)
        filename: '[name].js' (3)
    }
}

(1) entry就是入口文件,即我要把哪些文件进行构建,这里一般是你的项目入口文件。index.js就是项目入口文件,webpack会从它开始,一个个找到与它相关的文件,然后进行编译, 注意这里的路径,一定不要写成 index.js,要写成./index.js,相对于webpack.config.js
(2) output就是输出的js目录路径,一般都填个绝对路径 (__dirname指的是webpack.config.js所在的目录)。
(3) 输出文件名称[name]指代的是entry中的键名bundle(bundle.js)

5、在相对于webpack.config.js的路径建立index.js,输入var x = 10 在webpack.config.js所在目录,cmd执行webpack,构建完成后,此目录下生成了build文件假,里面存放了bundle.js

构建之前

这里写图片描述

1、本地安装后会在当前目录下载一个node_modules文件夹,当在项目里用require(‘webpack’),它会依次找当前目录下的node_module,然后再找它的父文件夹的node_modules,最后到根目录去寻找node_modules,比如我在我的F盘下面的Project目录的项目里用了require, 那么它的寻找路径就为[ ‘F:\Project\node_modules’,’F:\node_modules’ ],如果在 我的电脑->环境变量 -> 系统变量 -> 增加一个NODE_PATH,如果require没有找到相应模块,那么最后搜索NODE_PATH,我把它设置为我的全局安装的模块路径。那么也可不用本地下载,requie也能找到。【全局安装的模块路径】:打开nodejs安装目录/node_modules/npm/npmrc这个文件,里面就是全局安装的路径,我的是prefix=${APPDATA}\npm,在cmd里面echo %APPDATA%就能看到路径了我的电脑里面是C:\Users\Administrator\AppData\Roaming\npm\node_modules。
2、npm -v 的版本为3以上的话,下载包的依赖包是平行的,这样的好处就是文件夹之间不会层层嵌套,层层嵌套的文件夹会有不可复制且难以删除的麻烦,node_modules可复制就代表在别的项目下不用重新下载)
3、filename也可以写成[name].[hash].js,这时候[hash]是根据index.js内容生成,如果内容变化,hash值也会变化,此作用是为了强制更新浏览器缓存

es6和react

webpack的作用是构建,以reactJS为例,你要用reactJS框架,而且还要用JSX语法,那就要引入相应的框架。我们直接在需要用到react的js文件里面用var react = require(“react”),或者 import React from ‘react’( es6的语法)。

依赖包
react@16.2.0
react-dom@16.2.0
babel-preset-react@6.24.1
babel@6.23.0
babel-loader@7.1.4
babel-core@6.26.0
babel-preset-es2015@6.24.1
babel-polyfill@6.26.0
babel-preset-stage-0@6.24.1

1、 在根目录里面建立一个main.html, script引用bundle.js(这个就是最后构建好的js文件)

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

2、 在项目目录下载react,react-dom插件npm install react react-dom --save-dev,然后为了解析react,我们需要babel用于解析es6语法,和针对React的所有的预设插件
npm install babel babel-loader babel-core babel-preset-es2015 --save-dev
npm install babel-preset-react --save-dev
npm install babel-preset-stage-0 --save-dev

babel-preset-stage-0这个包含最新语法,stage-n n越在后面,它就越规范,有些新特性就没有,如果想用所有新特性,直接stage-0。

babel-preset-react是react语法包,这个包,是专门作为react的优化,让你在代码中可以使用React ES6 classes的写法和JSX语法。

用淘宝镜像下载得很快

3、实验es6语法,修改index.js内容如下:

{
    let s = 10;

    setTimeout(() => {
        alert(s)
    },1000)
}

webpack.config.js增加一个module配置项,如下:

var webpack = require('webpack');
module.exports = {
    entry: {
        bundle: './index.js',
    },
    output: {
        path: __dirname + '/build/',
        filename: '[name].js'
    },
    module: {
        loaders: [          (1)
            {
                test: /\.js$/,         
                loader:'babel-loader',  (2)
                exclude: /node_modules/
            }
        ]
    }
}

(1):loaders就是构建器,代表哪些文件用哪些构建器,这里的意思是把(test: /.js$/) 以.js为结尾的文件用’babel’插件进行构造但是构造过程/node_modules/这个文件里面的.js结尾文件不进行处理。 loaders是一个数组, 里面可以指定对css, scss, png等文件的构建处理。
(2):这是1年前做的笔记,当时这里loader填写的是babel,但是编译时报错
The node API for babel has been moved to babel-core
这一年里面nodeJS已经升级到8.9.3,npm 是5.5.1 ,webpack的版本都到3.3.10.0,简直太快了。在stackoverflow里面找到解决方法,换成babel-loader

4、webpack构建,完成后打开build文件夹查看是否正确编译,然后在浏览器中打开main.html,1秒后弹出10
增加mian.html

5、下面我们实验react,此时需要在项目根目录创建一个.babelrc文件,和package.json同级, 内容如下:

{
    presets: ['es2015','stage-0','react']
}

表示bable构建器接受stage-0,react的语法并将其构建成es5语法。(个人如此理解, 有更正确的理解请指出),具体配置可参照http://babeldev.dan.cx/docs/usage/babelrc/,此文件是比较关键。

6、修改index.js的内容变成:

import React,{Component} from 'react'
import { render } from 'react-dom'

class Box extends React.Component{

    render(){
        return (
            <h1>just pretend i am a box</h1>
        )
    }
}


render(
    <Box />,
    document.getElementById("main")
)

增加.babelrc
7、执行构建命令webpack, 最后在浏览器中打开main.html, 会发现id=main的div下面有h1元素了。

一年前React.createClass还能用,现在废弃了,直接就报错了。简直了……,介绍一个react中文网站给大家参阅下https://doc.react-china.org/docs/hello-world.html

8、更进一步,高级的es6,构造器和asycn函数, 这2二个是异步控制神器, 具体请访问http://es6.ruanyifeng.com/,,着重看‘Generator’, ’Promie‘,‘异步操作和Async函数‘三个章节,我们将index.js改写如下

function* gen(){
    var x = yield 10;
    var y = yield 20;
    var z = x + y;
    return z
}

let g = gen()
let x, y, z;
x = g.next().value;
y = g.next(x).value;
z = g.next(y).value;
alert(z)

构建成功后,main.html控制台却报Uncaught ReferenceError: regeneratorRuntime is not defined
这是因为我们少了一个垫片babel-polyfill。
npm install babel-polyfill --save-dev
然后在index.js里面引入

import "babel-polyfill"

function* gen(){
    var x = yield 10;
    var y = yield 20;
    var z = x + y;
    return z
}

let g = gen()
let x, y, z;
x = g.next().value;
y = g.next(x).value;
z = g.next(y).value;
alert(z)
//此时会弹出30

如果入口文件index.js开头引入import "babel-polyfill",但是用到ES7的async函数仍然报错:
regeneratorRuntime is not defined
试试将bable-polyfill放到webpack.config.js中,入口文件的import “babel-polyfill”可以删掉

...
entry: {
    bundle: ['babel-polyfill','./index.js']
},
...

在项目入口文件的开头即index.js里面引用它,然后通过入口文件import进来的的其他业务逻辑文件也可以被babel-polyfill支持使得生成器函数和异步函数可用。我们可以理为一开始就加载了一个组件js库,在这之后加载的js文件都可以用这个库.。

CSS样式

依赖包
style-loader@0.20.3
css-loader@0.28.11(处理css)

1、在根目录下创建文件夹css, 在css文件夹里面创建一个main.css

h1{color:red}

增加css

2、在webpack.config.js的loaders增加对css的处理,修改为:

var webpack = require('webpack');
module.exports = {
    entry: {
        bundle: './index.js',
    },
    output: {
        path: __dirname + '/build/',
        filename: '[name].js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,         
                loader:'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                loader: "style-loader!css-loader" (1) 
            }
        ]
    }
}

(1):将.css文件先经过css-loader处理,然后再经过style-loader处理,style-loader就是在webpack运行时遇到require(“main.css”)时,把这个文件的样式用style包裹插入到index.html的head标签下,css-loader的作用就是把url和@import翻译成requier。例如:url(image.png) => require(“./image.png”).

3、修改index.js的内容如下:

import "babel-polyfill"
import React,{Component} from 'react'
import { render } from 'react-dom'

require("./css/main.css") (1)

class Box extends React.Component{
    render(){
        return (
            <h1>just pretend i am a box</h1>
        )
    }
}
render(
    <Box />,
    document.getElementById("main")
)

(1):引入main.css,这里要用require语法不能用import,因为import是es6语法,import的是js文件,且js文件中需要定义export。

4、在命了行输入webpack进行构建,然后打开main.html,会看到样式生效,通过元素选择器去查看dom元素,发现html中多了个style标签。

讲一讲publicPath

依赖包
url-loader@1.0.1
file-loader@1.1.11

1、npm install url-loader file-loader --save-dev, 并且在根目录建立images文件夹,这里是作为开发时存放图片资源
新建images文件夹

images结构

2、修改main.css如下:

h1{color:green;height:200px;background:url('../images/test/test.png')}

3、修改webpack.config.js的配置如下

var webpack = require('webpack');
module.exports = {
    entry: {
        bundle: './index.js',
    },
    output: {
        path: __dirname + '/build/',
        filename: '[name].js',
        publicPath: "./build/" (1)
    },
    module: {
        loaders: [
            {
                test: /\.js$/,         
                loader:'babel',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                loader: "style-loader!css-loader" (1) 
            },
            {
                test: /\.(png|jpg)$/,
                loader: 'url-loader?limit=8192&name=distImg/[name].[ext]' (2)
            }
        ]
    }
}

(1):publicPath指定的路径会在打包的时候,将url-loader处理过后的文件进行重新定向。css里面的url形式如果是相对路径形式:url(../images/test/test.png),且图片大于8192K,构建时指定了publicPath,构建后在浏览器中打开main.html用dom探查器查看style标签里面的css,图片url被替换成了publicPath/[name],name就是打包图片时,指定的name(distImg/[name].[ext]),所以这里应该看到url(./build/distImg/test.png),”./build/”是publicPath,”distImg/test.png“是name。
(2):url-loader会让小于8KB(8129bits)的图片将直接以base64的形式内联在代码中,一般限制小图片转 base64 可以用 url-loader,其他情况都用 file-loader,url-loader应该是file-loader上加了一层过滤。在这里file-loader虽然并未在webpack.config.js中明确指出来,但是在项目过程中发现url-loader好像依赖file-loader,所以file-loader也需要下载 name=distImg/[name].[ext]表示图片会被打包到打包目录下,并建立一个distImg文件夹,打包后的图片在此文件夹下。
在这个例子中,图片路径是envtest/images/test/test.png,main.css里面 用../images/test/test.png来找到图片,构建后在build目录下,产生了distImg/test.png,由于此种方法是将css内嵌到style标签,main.html去找就需要用./build/distImg/test.png,所以publicPath设置为 “./build/distImg”

提取css

依赖包
extract-text-webpack-plugin@3.0.2

1、下载插件npm install extract-text-webpack-plugin –save-dev,,extract-text-webpack-plugin用于提取css为单一文件

2、修改webpack.config.js

var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin'); (1)

module.exports = {
    entry: {
        bundle: './index.js'
    },
    output: {
        path: __dirname + '/build/',
        filename: '[name].js',
        publicPath: './' (2)
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract("css-loader”,”style-loader") (3)
            },
            {
                test: /\.(png|jpg)$/,
                loader: 'url-loader?limit=8192&name=distImg/[name].[ext]'
            }
        ]
  },
  plugins:[
        new ExtractTextPlugin('prefixer_main.css', {    (4)
           disable: false,
           allowChunks: true
        })
    ]
}

(1):引入ExtractTextPlugin
(2):由于css打包成一个单独文件在build目录,publicPath需要改变下
(3):用ExtractTextPlugin.extract方法将css由css-loader处理后提取出出来,如果提取失败,则用style-loader处理,即以内联样式插入到index.html中。以前是 ExtractTextPlugin.extract(“style-loader”,”css-loader”)现在需要写成ExtractTextPlugin.extract(“css-loader”,”style-loader”),否则报错:
Module build failed: ModuleParseError:Module parse failed: Unexpected token (1:2)
You may need an appropriate loader to handle this file type
(4):用ExtractTextPlugin将css提取为perefixer_main.css,并放在output.path下。
它将从每一个用到了require(“*.css”)的entry chunks文件中抽离出css到单独的output文件

提取css放入build目录下

由于此时css单独提取出来,则在prefixer_main.css需要通过./distImg/test.png才能引用到图片,所以publicPath= ‘./’。

3、修改main.html,在head头部添加

<link rel="stylesheet" href="./build/prefixer_main.css" type="text/css" />

4、打开main.html,展示正确,打开prefixer_main.css,看到图片路径变成了url(./distImg/test.png)。

发布

只需要将main.html和build目录部署到生产就可以了,其他文件不用部署
部署的文件

小结

下一篇会介绍如何使用热刷新,提前吐槽下,这个是1年前做的笔记,特地翻出来照着配置一遍,由于版本升级太多做了些修改,其中最坑的修改时webpack和webpack-dev-server的版本适配太奇葩,webpack是3.x.x的话,webpack-dev-server就必须是2.x.x。webpack是4.x.x的话,webpack-dev-server就是3.x.x。这个还是翻了好多帖子才找到的,原贴主人说是在google里面才能找到。

附上此项目git:https://github.com/kiramario/hello-world.git

阅读更多
换一批

没有更多推荐了,返回首页