webpack打包react項目添磚加瓦

(一)首先實現編譯react文件,編譯並分離scss文件,靜態文件的形式訪問index.htmljavascript

1. 各類路徑信息存儲在config.js文件中css

2. gulp文件:引入config.js, 引入webpack.config.js, 引入gulp-webpack包html

gulp default執行:java

gulp.task('webpack', function() {
  gulp.src('')
    .pipe(webpack(webpackConfig()))
    .pipe(gulp.dest(config.jsDistDir));
});

gulp.task('default', ['webpack']);

3. webpack.config.jsnode

module.exports = function() {
  return  {
    watch: true,
    entry: {
      'index/index.page': './src/js/src/page/index/index.page.jsx',
      'detail/index.page': './src/js/src/page/detail/index.page.jsx' //打包入口文件。entry對象key實際上是目標路徑的一部分。key也能夠是絕對路徑。
    },
    output: {
      path: config.jsDistDir, //目標文件地址
      filename: "[name].js" //name是entry對象的key
    },
    externals: {
      react: 'React',
      reactDOM: 'ReactDOM',
      'react-dom': 'ReactDOM' //不被打包的文件。目前react的引用方式是index.html中經過script標籤引入。經實踐,去掉externals對webpack打包沒影響。
    },
    module: {
      loaders: [{
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loaders: ['babel?presets[]=react'] //loaders,編譯react文件
      }, {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract('style-loader', 
        'css!sass')
      }]
    },
    resolve: {
      alias: getAlias(),
      extensions: ["", ".min.js", ".js", ".jsx"]
    },
    plugins: [
      new ExtractTextPlugin('[name].css', {
        allChunks: true
      })
    ],
    devtool: 'source-map'
  }
}

4.能夠在jsx文件中直接require.scss文件: sass-loader編譯scss文件, css-loader讓css文件能夠做爲模塊引入,extractTextPlugin將css抽取問一個獨立文件,能夠在head中經過link方式引入react

5. resolve中的alias能夠爲模塊取別名。一些自定義的模塊能夠不經過文件路徑而經過別名的方式來引用。getAlias是自定義函數,實現了filename-filePath的mapwebpack

(二)加入expressweb

1. 設置serve任務express

gulp.task('serve', function() {
  var app = express();
  app.use(appConfig.jsPath, headerStatic(path.join(appConfig.webapp, appConfig.jsPath), {})); //js路徑映射
  app.use(appConfig.cssPath, headerStatic(path.join(appConfig.webapp, appConfig.cssPath), {}));//css路徑映射
  app.use("", headerStatic(appConfig.webapp, {}));//html, 放在webapp目錄下
  gulp.run('webpack');//打包
  app.listen(8082, function(err) { //監聽請求
    if (err) { return console.log(err); }
    console.log('listening on %d', 8082);
  });
});

2. headerStatic函數返回一個函數,這個函數根據請求req返回靜態文件。json

function headerStatic(staticPath, headers) {
  return function(req, res, next) {
    var reqPath = req.path === '/' ? 'index' : req.path;
    var f = path.join(staticPath, reqPath);
    //設置不一樣的contentType
    if (fs.existsSync(f)) {
      if (/\.html$/.test(reqPath)) {
        res.set('Content-Type', 'text/html');
        res.send(fs.readFileSync(f, 'utf-8'));
      } else {
        if (/\.js$/.test(reqPath)) {
          res.set('Content-Type', 'text/javascript');
          res.send(fs.readFileSync(f, 'UTF-8'));
        } else if (/\.css$/.test(reqPath)) {
          res.set('Content-Type', 'text/css');
          res.send(fs.readFileSync(f, 'UTF-8'));
        } else {
          res.send(fs.readFileSync(f));
        }
      }
    } else {
      next();
    }
  } 
}

(三)build  

 1. 在這個demo中build的過程很簡單,包括:clean, webpack, uglifyjs, minifyCss, revision-css, revision-js, revreplace-html。

 2. 這幾個步驟分別以下實現:

clean: 清空上次打包生成的文件

gulp.task('clean', function() {
  return gulp.src([tmp1, tmp2, appConfig.build], {read: false}).pipe(clean()); //tmp1, tmp2是生成目標文件的中間目錄,appConfig.build是存放最終打包好的文件的位置。每一個項目是否須要中間目錄及中間目錄的路徑是自定義的
});

webpack: 編譯js文件。在咱們的demo中,打包後的文件在目錄/.tmp/step1/js/dist下

uglifyjs: 壓縮js文件。壓縮後的文件仍在tmp1下

gulp.task('uglifyjs', function() {
  return gulp.src(path.join(tmp1, '**/*.js'))
              .pipe(gulpif(uglifyJs, uglify().on('error', util.log))) //gulpif: 第一個參數是函數。若是返回true, 執行後面的語句
              .pipe(gulp.dest(tmp1));
});

minifyCss: 壓縮css文件

壓縮後的css文件也在tmp1下。

gulp.task('minifyCss', function() {
  return gulp.src(path.join(tmp1, '**/*.css'))         
         .pipe(minifyCss())
         .pipe(gulp.dest(tmp1));
});

revision-css, revision-js: 爲js和css文件追加hash後綴標識版本

gulp.task('revision-css', function() {
  return gulp.src(path.join(tmp1, '**/*.css'))
         .pipe(rev())
         .pipe(gulp.dest(tmp2))  //加過版本號的css文件拷貝到tmp2目錄下
         .pipe(rev.manifest('style-rev-manifest.json')) //生成原有文件名與revision後的文件名的map
         .pipe(gulp.dest(tmp2));        
});

gulp.task('revision-js', function() {
  return gulp.src(path.join(tmp1, '**/*.js'))
          .pipe(rev())
          .pipe(gulp.dest(tmp2))
          .pipe(rev.manifest('js-rev-manifest.json'))
          .pipe(gulp.dest(tmp2));  
});

 revreplace-html: 把html文件中對js和css文件的引用替換爲最新版本。輸出目標爲tmp2

gulp.task('revreplace-html', function() {
  var manifest = gulp.src([
    path.join(tmp2, '/style-rev-manifest.json'),
    path.join(tmp2, '/js-rev-manifest.json')
  ]);

  return gulp.src(path.join(appConfig.webapp, '**/*.html'))
        .pipe(revReplace({
          manifest: manifest,
          replaceInExtensions: ['.html']
        }))
        .pipe(gulp.dest(tmp2));
});

(四)livereload: 文件更新後自動刷新頁面

function watchFiles(ext) {
  gulp.watch(path.join(config.webappDir, '**/*.' + ext), function(event) {
    tinylr.changed(event.path);
  });
}

//gulp task serve中
app.use(body()).use(tinylr.middleware({ //tinylr = require('tiny-lr');
    app: app
}));

watchFiles('js');
watchFiles('html');

  

以上,這個簡單的demo能夠經過gulp serve啓動本地調試環境,經過gulp build構建生產環境的文件

相關文章
相關標籤/搜索