其实只要在最终的html页面中加载了插件,任何component.ts的生命周期内部都可以直接用正确语法(比如改写var成let)抄写普通的js,new一个插件什么的,只是编译时会报找不到变量的红字,编译后完全functional...

我是在组件ts里面写require的,只要不报没有这个module,定义一下用到的变量后终于把找不到$和Swiper的红字给消了。

let $ = require('jquery');
let Swiper = require('Swiper');

这个require要成功必须在webpack.config中设置

module.exports = {
externals:[ { $:
"jQuery" }, { jQuery:"jQuery" }, { window: "window"}, { Swiper: "Swiper"}, ],

如果是index.html里面<script>了jquery和swiper的话就不需用到loader(是否只是避免了编译时报错而并没有实际获取到jquery对象)

var webpack = require('webpack');
var autoprefixer = require('autoprefixer');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  //devtool : 'inline-source-map',
  entry: {
        main:['./app/main.ts',
        './app/sass/main.scss',
        './app/sass/home.scss',
        './app/sass/personal.scss',
        ],
        vendor:[
            
        ]
  },
  externals:[
    { $:"jQuery" },
    { jQuery:"jQuery" },
    { window: "window"},
    { Swiper: "Swiper"},
  ],
  output: {
    path: './dist',
    filename: 'js/app.bundle.js',
    publicPath:'/',
    libraryTarget: "var"
  },
  module: {
    loaders: [
      {test: /\.ts$/, loader: 'ts'},
      {test: /\.html$/, loader: 'raw'},
      {test: /\.css$/, loader: ExtractTextPlugin.extract('style', 'css!postcss')},
      {test: /\.scss$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")},
      {
        test: require.resolve("./dist/assets/js/jquery.min.js"),
        loader: "imports-loader?jQuery=>jquery"
      },
      {
        test: require.resolve("./dist/assets/js/swiper.jquery.js"),
        loader: 'imports-loader?Swiper=>swiper'
      }
    ]
  },
  postcss: [autoprefixer()],
  resolve: {
    extensions: ['', '.js', '.ts', '.scss'],
    //alias: { jquery: "assets/js/jquery.min.js"}
  },
  plugins: [
    new ExtractTextPlugin("assets/css/[name].css", {publicPath: '/assets/',allChunks: true}),
    new HtmlWebpackPlugin({template: './app/index.html'}),
    new webpack.optimize.CommonsChunkPlugin({
        name: "vendor",
        //filename : 'vendor_[chunkhash].js',
        filename : 'js/vendor.js',
        minChunks: Infinity
    }),
    new webpack.ProvidePlugin({
        // $: "jquery",
        // jQuery: "jquery",
        // "window.jQuery": "jquery"
    }),
    /*new webpack.optimize.UglifyJsPlugin({
        compress: {
            warnings: false
        }
    }),*/
    new webpack.DefinePlugin({
      app: {
        environment: JSON.stringify(process.env.APP_ENVIRONMENT || 'development')
      }
    })
  ]
};
webpack.config

上面是用的 imports,换做expose:

{ test: require.resolve("./dist/assets/js/jquery.min.js"), loader: "expose?$!expose?jQuery" },
{ test: require.resolve("./dist/assets/js/swiper.jquery.js"), loader: "expose?Swiper" }

为了达到按需加载的目的...但是loader总也不起作用呀!是RP问题吗?

我曾经试着在entry里面像import上面那些scss那样引入要用的插件,实验证明完全没有意义:

1.不能激活loader制造模块

2.不能代替html中引用script

3.不能使得ts正确import到模块

4.不能使得ts正确require到模块

查了那么多资料最终还是离不开直接在html里面引用html...

后来用到有一段扩展jquery的代码

// JavaScript Document
/*
 * award Rotate - jQuery plugin for award Rotate
 */

(function($) {
var supportedCSS,styles=document.getElementsByTagName("head")[0].style,toCheck="transformProperty WebkitTransform OTransform msTransform MozTransform".split(" ");
for (var a=0;a<toCheck.length;a++) if (styles[toCheck[a]] !== undefined) supportedCSS = toCheck[a];
// Bad eval to preven google closure to remove it from code o_O
// After compresion replace it back to var IE = 'v' == '\v'
var IE = eval('"v"=="\v"');

jQuery.fn.extend({
    rotate:function(parameters)
    {
        if (this.length===0||typeof parameters=="undefined") return;
            if (typeof parameters=="number") parameters={angle:parameters};
        var returned=[];
        for (var i=0,i0=this.length;i<i0;i++)
            {
                var element=this.get(i);    
                if (!element.Wilq32 || !element.Wilq32.PhotoEffect) {

                    var paramClone = $.extend(true, {}, parameters); 
                    var newRotObject = new Wilq32.PhotoEffect(element,paramClone)._rootObj;

                    returned.push($(newRotObject));
                }
                else {
                    element.Wilq32.PhotoEffect._handleRotation(parameters);
                }
            }
            return returned;
    },
    getRotateAngle: function(){
        var ret = [];
        for (var i=0,i0=this.length;i<i0;i++)
            {
                var element=this.get(i);    
                if (element.Wilq32 && element.Wilq32.PhotoEffect) {
                    ret[i] = element.Wilq32.PhotoEffect._angle;
                }
            }
            return ret;
    },
    stopRotate: function(){
        for (var i=0,i0=this.length;i<i0;i++)
            {
                var element=this.get(i);    
                if (element.Wilq32 && element.Wilq32.PhotoEffect) {
                    clearTimeout(element.Wilq32.PhotoEffect._timer);
                }
            }
    }
});

// Library agnostic interface

Wilq32=window.Wilq32||{};
Wilq32.PhotoEffect=(function(){

    if (supportedCSS) {
        return function(img,parameters){
            img.Wilq32 = {
                PhotoEffect: this
            };
            
            this._img = this._rootObj = this._eventObj = img;
            this._handleRotation(parameters);
        }
    } else {
        return function(img,parameters) {
            // Make sure that class and id are also copied - just in case you would like to refeer to an newly created object
            this._img = img;

            this._rootObj=document.createElement('span');
            this._rootObj.style.display="inline-block";
            this._rootObj.Wilq32 = 
                {
                    PhotoEffect: this
                };
            img.parentNode.insertBefore(this._rootObj,img);
            
            if (img.complete) {
                this._Loader(parameters);
            } else {
                var self=this;
                // TODO: Remove $ dependency
                $(this._img).bind("load", function()
                {
                    self._Loader(parameters);
                });
            }
        }
    }
})();

Wilq32.PhotoEffect.prototype={
    _setupParameters : function (parameters){
        this._parameters = this._parameters || {};
        if (typeof this._angle !== "number") this._angle = 0 ;
        if (typeof parameters.angle==="number") this._angle = parameters.angle;
        this._parameters.animateTo = (typeof parameters.animateTo==="number") ? (parameters.animateTo) : (this._angle); 

        this._parameters.step = parameters.step || this._parameters.step || null;
        this._parameters.easing = parameters.easing || this._parameters.easing || function (x, t, b, c, d) { return -c * ((t=t/d-1)*t*t*t - 1) + b; }
        this._parameters.duration = parameters.duration || this._parameters.duration || 1000;
        this._parameters.callback = parameters.callback || this._parameters.callback || function(){};
        if (parameters.bind && parameters.bind != this._parameters.bind) this._BindEvents(parameters.bind); 
    },
    _handleRotation : function(parameters){
          this._setupParameters(parameters);
          if (this._angle==this._parameters.animateTo) {
              this._rotate(this._angle);
          }
          else { 
              this._animateStart();          
          }
    },

    _BindEvents:function(events){
        if (events && this._eventObj) 
        {
            // Unbinding previous Events
            if (this._parameters.bind){
                var oldEvents = this._parameters.bind;
                for (var a in oldEvents) if (oldEvents.hasOwnProperty(a)) 
                        // TODO: Remove $ dependency
                        $(this._eventObj).unbind(a,oldEvents[a]);
            }

            this._parameters.bind = events;
            for (var a in events) if (events.hasOwnProperty(a)) 
                // TODO: Remove $ dependency
                    $(this._eventObj).bind(a,events[a]);
        }
    },

    _Loader:(function()
    {
        if (IE)
        return function(parameters)
        {
            var width=this._img.width;
            var height=this._img.height;
            this._img.parentNode.removeChild(this._img);
                            
            this._vimage = this.createVMLNode('image');
            this._vimage.src=this._img.src;
            this._vimage.style.height=height+"px";
            this._vimage.style.width=width+"px";
            this._vimage.style.position="absolute"; // FIXES IE PROBLEM - its only rendered if its on absolute position!
            this._vimage.style.top = "0px";
            this._vimage.style.left = "0px";

            /* Group minifying a small 1px precision problem when rotating object */
            this._container =  this.createVMLNode('group');
            this._container.style.width=width;
            this._container.style.height=height;
            this._container.style.position="absolute";
            this._container.setAttribute('coordsize',width-1+','+(height-1)); // This -1, -1 trying to fix ugly problem with small displacement on IE
            this._container.appendChild(this._vimage);
            
            this._rootObj.appendChild(this._container);
            this._rootObj.style.position="relative"; // FIXES IE PROBLEM
            this._rootObj.style.width=width+"px";
            this._rootObj.style.height=height+"px";
            this._rootObj.setAttribute('id',this._img.getAttribute('id'));
            this._rootObj.className=this._img.className;            
            this._eventObj = this._rootObj;    
            this._handleRotation(parameters);    
        }
        else
        return function (parameters)
        {
            this._rootObj.setAttribute('id',this._img.getAttribute('id'));
            this._rootObj.className=this._img.className;
            
            this._width=this._img.width;
            this._height=this._img.height;
            this._widthHalf=this._width/2; // used for optimisation
            this._heightHalf=this._height/2;// used for optimisation
            
            var _widthMax=Math.sqrt((this._height)*(this._height) + (this._width) * (this._width));

            this._widthAdd = _widthMax - this._width;
            this._heightAdd = _widthMax - this._height;    // widthMax because maxWidth=maxHeight
            this._widthAddHalf=this._widthAdd/2; // used for optimisation
            this._heightAddHalf=this._heightAdd/2;// used for optimisation
            
            this._img.parentNode.removeChild(this._img);    
            
            this._aspectW = ((parseInt(this._img.style.width,10)) || this._width)/this._img.width;
            this._aspectH = ((parseInt(this._img.style.height,10)) || this._height)/this._img.height;
            
            this._canvas=document.createElement('canvas');
            this._canvas.setAttribute('width',this._width);
            this._canvas.style.position="relative";
            this._canvas.style.left = -this._widthAddHalf + "px";
            this._canvas.style.top = -this._heightAddHalf + "px";
            this._canvas.Wilq32 = this._rootObj.Wilq32;
            
            this._rootObj.appendChild(this._canvas);
            this._rootObj.style.width=this._width+"px";
            this._rootObj.style.height=this._height+"px";
            this._eventObj = this._canvas;
            
            this._cnv=this._canvas.getContext('2d');
            this._handleRotation(parameters);
        }
    })(),

    _animateStart:function()
    {    
        if (this._timer) {
            clearTimeout(this._timer);
        }
        this._animateStartTime = +new Date;
        this._animateStartAngle = this._angle;
        this._animate();
    },
    _animate:function()
    {
         var actualTime = +new Date;
         var checkEnd = actualTime - this._animateStartTime > this._parameters.duration;

         // TODO: Bug for animatedGif for static rotation ? (to test)
         if (checkEnd && !this._parameters.animatedGif) 
         {
             clearTimeout(this._timer);
         }
         else 
         {
             if (this._canvas||this._vimage||this._img) {
                 var angle = this._parameters.easing(0, actualTime - this._animateStartTime, this._animateStartAngle, this._parameters.animateTo - this._animateStartAngle, this._parameters.duration);
                 this._rotate((~~(angle*10))/10);
             }
             if (this._parameters.step) {
                this._parameters.step(this._angle);
             }
             var self = this;
             this._timer = setTimeout(function()
                     {
                     self._animate.call(self);
                     }, 10);
         }

         // To fix Bug that prevents using recursive function in callback I moved this function to back
         if (this._parameters.callback && checkEnd){
             this._angle = this._parameters.animateTo;
             this._rotate(this._angle);
             this._parameters.callback.call(this._rootObj);
         }
     },

    _rotate : (function()
    {
        var rad = Math.PI/180;
        if (IE)
        return function(angle)
        {
            this._angle = angle;
            this._container.style.rotation=(angle%360)+"deg";
        }
        else if (supportedCSS)
        return function(angle){
            this._angle = angle;
            this._img.style[supportedCSS]="rotate("+(angle%360)+"deg)";
        }
        else 
        return function(angle)
        {
            this._angle = angle;
            angle=(angle%360)* rad;
            // clear canvas    
            this._canvas.width = this._width+this._widthAdd;
            this._canvas.height = this._height+this._heightAdd;
                        
            // REMEMBER: all drawings are read from backwards.. so first function is translate, then rotate, then translate, translate..
            this._cnv.translate(this._widthAddHalf,this._heightAddHalf);    // at least center image on screen
            this._cnv.translate(this._widthHalf,this._heightHalf);            // we move image back to its orginal 
            this._cnv.rotate(angle);                                        // rotate image
            this._cnv.translate(-this._widthHalf,-this._heightHalf);        // move image to its center, so we can rotate around its center
            this._cnv.scale(this._aspectW,this._aspectH); // SCALE - if needed ;)
            this._cnv.drawImage(this._img, 0, 0);                            // First - we draw image
        }

    })()
}

if (IE)
{
Wilq32.PhotoEffect.prototype.createVMLNode=(function(){
document.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
        try {
            !document.namespaces.rvml && document.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
            return function (tagName) {
                return document.createElement('<rvml:' + tagName + ' class="rvml">');
            };
        } catch (e) {
            return function (tagName) {
                return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
            };
        }        
})();
}

})($);
awardRotate.js

执行的语句插入到component的export Class时,果然之前let的虚假定义露出了马脚:

报错 :“此jquery对象只是一个enhanced的对象。。”

很奇怪的是这个被我let出来require("jquery")的$却是实实在在的获取得到dom对象,还能打印出来,但是对于扩展以后的方法,$().rotate,就会报没有这个方法。我把扩展js放在vendor入口里面,确确实实在调试窗口sources查看了vendor.js包含进去以后,也没还是找不到扩展的方法。

于是我决心再倒腾一下imports-loader,最后可能还是由于angular2.0的版本问题,毕竟不是最新的,这样写,是给所有ts文件导入jquery了:

var webpack = require('webpack');
var autoprefixer = require('autoprefixer');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  //devtool : 'inline-source-map',
  entry: {
        main:['./app/main.ts','./app/sass/main.scss'],
        vendor:[
                './dist/assets/js/mobile-base.js',
                './dist/assets/js/awardRotate.js'
        ]
  },
  externals:[
    { $:"jQuery" },
    { jQuery:"jQuery" },
    { window: "window"},
    { Swiper: "Swiper"},
  ],
  output: {
    path: './dist',
    filename: 'js/app.bundle.js',
    //publicPath:'http://localhost:8000',
    libraryTarget: "var"
  },
  module: {
    loaders: [
      {test: /\.ts$/, loader: 'ts!imports?$=jquery'},
      {test: /\.html$/, loader: 'raw'},
      {test: /\.css$/, loader: ExtractTextPlugin.extract('css-loader?sourceMap')},
      {test: /\.scss$/, 
loader: ExtractTextPlugin.extract('css-loader?sourceMap!postcss-loader!sass-loader?outputStyle=compressed')
}, {test:
/\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/, loader:"url-loader?limit=8192"}, {test: /vendor\/.+\.(jsx|js)$/, loader: 'imports?this=>window' }
//有的版本!是用,号的语法写错loader是不会有作用呢的,上面这里加上 |ts 貌似也没起作用,费解,总之这个配置是起效的 ] }, ... ... ... ...

imports-loader

https://github.com/webpack/imports-loader

https://github.com/webpack/docs/wiki/shimming-modules

https://github.com/webpack/webpack/issues/542

Modularisation system is a part of every modern language that is used for creating complex applications. javascript is special here - modularisation system is not a part of language itself . We got great standards ( CommonJS or AMD ) and tools to make modularisation work. One of the most popular is Webpack - a module bundler which comes with variety of so-called loaders , transforming the input code.

Unfortunately modularisation systems not within the language creates compatibility problems . There are libraries that can’t understand modules and assumes that dependencies are available globally under predefined names.

I had this issue today. I wanted to use the great Chosen library for multi-select inputs. Unfortunately Chosen expects to have jQuery defined in the global namespace and is unaware of modules at all. In this article I’d like to show you how to integrate such module-unaware libraries with Webpack without introducing global variables.

Goal & Initial State

My goal was to allow Chosen to extend my jQuery instance without exposing the jQuery instance as a global. I have jQuery in my project installed using npm install --save jquery command - as a module. So every time I need to use jQuery I need to import it manually (here, using ES2015 syntax):

import $ from 'jquery';

Chosen can come as a bower package or as a standalone JS file with some CSS files and images attached. I decided to take the latter approach and put it into a vendor/ folder in my project. So I put the chosen.jquery.js file into the vendor folder.

As have been said before, chosen.jquery.js does not understand modules - it needs to have jQuery defined under jQuery name in global namespace. With many libraries like that it is also desirable to have this pointing to the window variable which is not granted in many environments. For example Babel.js assumes that every input it takes is a ES2015 module and this is pointing to null in such case (more about it here ). So if you integrate babel-loader to use ES2015 syntax you may experience problems with such libraries.

Having this problem defined, let’s take a look how the perfect solution can be achieved - so have jQuery still as a module without exposing it as a global but being able to use libraries that assumes jQuery is defined as a global .

Solution - imports-loader

Webpack has a special loader for handling cases like that. It is called imports-loader and you need to install it by yourself - it doesn’t come by default when you install webpack . Fortunately the installation process is straightforward:

npm install --save-dev imports-loader

Then you need to modify your webpack config. In loaders section of your config you need to add the following code:

{ test: /vendor\/.+\.(jsx|js)$/, loader: 'imports?jQuery=jquery,$=jquery,this=>window' }
Let’s get through this loader definition. The first part, imports defines that we want to use imports-loader . After ? there is a list of values, separated by a comma. First one jQuery=jquery defines that under the jQuery variable in loaded code there will be a result of require("jquery") expression - in our case, our jQuery library from the module. The second one is the same, but the name is different. If you want to name your variable the same as your module, you can skip the part after the equation sign and the equation sign itself. So jquery would create a jquery variable with require("jquery") value in the loaded code.

The last value is about redefining the global variable. So global this will point to window in the loaded code. It is an equivalent of wrapping the whole contents of the file with the function(this) { ... } and calling this function in-place with window as an argument. You can do the same with any global variables and it is indicated by an arrow ( => ).

That’s it! Now I can do:

import $ from 'jquery'; import "vendor/chosen.jquery";
And I can use chosen jQuery extension without any problems!

Summary

As you can see, integrating module-unaware libraries without exposing its dependencies as globals is a rather simple task. In fact I thought it’ll be harder - I’ve seen many webpack configurations where popular libraries/frameworks like jQuery or Angular.js were exposed as global variables. I hope that you’ll be able to integrate your favourite libraries that way just like I did with Chosen.
一片被爬虫转载找不到原文的文章

expose-loader

http://blog.csdn.net/yiifaa/article/details/51916560

延伸阅读 

webpack中imports-loader,exports-loader,expose-loader的区别

exports-loader

shimming 在 AMD/CMD 中,我们需要对不符合规范的模块(比如一些直接返回全局变量的插件)进行 shim 处理,这时候我们需要使用 exports-loader 来帮忙: { test: require.resolve("./src/js/tool/swipe.js"), loader: "exports?swipe"} 之后在脚本中需要引用该模块的时候,这么简单地来使用就可以了: require('./tool/swipe.js'); swipe();

http://blog.csdn.net/yczz/article/details/49250623

posted on 2016-12-31 20:45  meeming  阅读(918)  评论(0编辑  收藏  举报



Fork me on GitHub