1. 程式人生 > >webpack+react+node採坑之旅 (上)

webpack+react+node採坑之旅 (上)

前言

之前一直以為能力已經夠了,想出去找份前端的工作,後來才發現還是自己太差,面試官隨便一個問題就能把我問啞,比如,webpack、gulp、grunt這些工具瞭解多少。這兩天學習webpack,踩了不少坑,也學到不少東西,記錄下來以便後查。

說明

本部落格記錄於2017.11.12,使用到的各個版本如下
- webpack:3.8.1
- node:v6.11.3
- react:^16.1.0

什麼是webpack

Webpack 是當下最熱門的前端資源模組化管理和打包工具。它可以將許多鬆散的模組按照依賴和規則打包成符合生產環境部署的前端資源。還可以將按需載入的模組進行程式碼分隔,等到實際需要的時候再非同步載入。通過 loader 的轉換,任何形式的資源都可以視作模組,比如 CommonJs 模組、 AMD 模組、 ES6 模組、CSS、圖片、 JSON、Coffeescript、 LESS 等。

開始

安裝與準備

下載node,裡面會整合npm,用npm下載webpack包。

npm install webpack -g

-g 表示全域性安裝

新建一個資料夾作為專案資料夾,在專案資料夾下shitf+滑鼠右鍵開啟命令列,在命令列輸入

npm init

提示全部跳過
提示跳過
這時資料夾裡會生成一個package.json檔案,這個檔案的作用是配置專案依賴的包,別人下載了你的專案,只需要npm install就可以直接下載專案依賴的包。

建立檔案目錄,目錄結構如下

  + blog
   + client
      + dist // 編譯並打包後的檔案
+ images + js + css + index.html // 前端入口檔案 + src + assets // 圖片等靜態資源 + components // 一些公用元件 + layouts // 一些佈局元件(括jsx和sass檔案),比如導航欄、側邊欄等等 + routes // 路由相關檔案 + routes.js + main.js // 整個前端專案的入口檔案 + server
// 服務端檔案 + package.json

接下來安裝相應的包。

npm install react react-dom redux react-redux react-router antd css-loader style-loader node-sass sass-loader file-loader url-loader autoprefixer postcss-loader  --save-dev
npm install extract-text-webpack-plugin path --save-dev

安裝babel外掛

npm install babel-loader babel-core babel-preset-es2015 babel-preset-react babel-preset-stage-1 babel-plugin-import babel-cli --save-dev

關於–save-dev與–save的區別是–save 會把依賴包名稱新增到package.json 檔案 dependencies 鍵下,–save-dev 則新增到 package.json 檔案 devDependencies 鍵下,dependencies是執行時依賴,devDependencies是開發時的依賴。

配置檔案

index.html檔案

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>hello world</title>
    <link rel="stylesheet" href="">

</head>
<body>
    <div id="app">a</div>
</body>
<script src="vendor.bundle.js" type="text/javascript"></script>
<script src="bundle.js" type="text/javascript" charset="utf-8"></script>
</html>

在專案根檔案目錄下新建webpack.config.js,配置大致如下

var webpack = require('webpack'),
    ExtractTextPlugin = require('extract-text-webpack-plugin'),
    path=require('path');
var config = {
    entry: { // 打包入口
        index: "./client/src/main.js",
        vendor: [  // 將react和react-dom這些單獨打包出來,減小打包檔案體積
            "react",
            "react-dom"
        ]
    },
    output:{//打包後的檔案
        path: path.resolve(__dirname,'./client/dist'),
        filename: 'bundle.js'
        //filename: '[name].js'
    },    
    module: {//打包檔案的配置
        loaders: [{    //將es6語法的js,jsx轉為es5js
            test: /\.js|.jsx$/,
            exclude: /node_modules/,
            loader: "babel-loader",   
            query:{
                presets:['es2015','react']
            }         
        }, 
        {
        test: /\.css$/,
        loader: 'style-loader!css-loader!autoprefixer-loader?{browsers:["last 2 version","firefox 15"]}'
        },
        {
            test: /\.(png|jpg|jpng|eot|ttf)$/, // 打包圖片和字型檔案
            loader: 'url-loader?limit=8192&name=images/[name].[ext]'
        }]
    },
    plugins: [//配置外掛
        new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' }), //這是之前單獨打包出來的react、react-dom等檔案
        new ExtractTextPlugin("css/index.css"), // 將所有sass/css檔案打包成一個index.css檔案
        new webpack.DefinePlugin({
            "process.env": { 
                NODE_ENV: JSON.stringify("production") 
            }
        }),
        new webpack.optimize.UglifyJsPlugin({ // 壓縮打包後的程式碼
            compress: {
                warnings: false
            }
        }),       
    ]
}
module.exports = config;

測試

在mian.js寫入以下程式碼

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
<div>hello,word</div>,
document.getElementById('app')
    )

開啟client/dist/index.html
開啟index

錯誤及解決

錯誤1

ERROR in ./client/src/main.js
Module build failed: SyntaxError: E:/node.js/react/1106ABegin/myTest/client/src/main.js: Unexpected token (5:0)

  3 |
  4 | ReactDOM.render(
> 5 | <div>hello,word</div>,
    | ^
  6 | document.getElementById('app')
  7 |   )
  8 |

解決:原因是jsx配置錯誤,在webpack.config.js中的module模組修改如下

loaders: [{    // babel loader
            test: /\.js|.jsx$/,
            exclude: /node_modules/,
            loader: "babel-loader",   //使用babel-loader需要下載相應模組
            query:{
                presets:['es2015','react']//這裡很重要
            }         
        }

錯誤2

Uncaught ReferenceError: webpackJsonp is not defined
    at bundle.js:1
(anonymous) @ bundle.js:1

解決:這裡是忘了引用依賴的包,我們在webpack.config.js中把react,react-dom打包成了vendor.bundle.js,所以我們需要在index.html中引入相應的包

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>hello world</title>
    <link rel="stylesheet" href="">

</head>
<body>
    <div id="app">a</div>
</body>
<script src="vendor.bundle.js" type="text/javascript"></script>
<script src="bundle.js" type="text/javascript" charset="utf-8"></script>
</html>

錯誤3
錯誤

解決:找了很久的錯誤,發現是在index.html中的引用js的時候必須把它放到文件末尾。
1