2
require( 'time-grunt' )( grunt );
require( 'load-grunt-tasks' )( grunt );

grunt.loadNpmTasks('grunt-debug-inspector');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-pug');

grunt.config.init( {
    debug: {
        options: {
          open: true // do not open node-inspector in Chrome automatically
        }
      },
    concurrent: {
        develop: {
            tasks: [ 'nodemon', 'watch' ],
            options: {
                logConcurrentOutput: true
            }
        }
    },
    nodemon: {
        dev: {
            script: 'app.js',
            options: {
                watch: [ 'app', 'config' ],
                nodeArgs: [ '--debug' ],
                env: {
                    NODE_ENV: 'development',
                    DEBUG: '*, -express:*, -send, -compression, -body-parser:*, -puppeteer:*'
                }
            }
        }
    },
    sass: {
        options: {
            implementation: nodeSass
        },
        compile: {
            cwd: 'app/views/styles',
            dest: 'public/css',
            expand: true,
            outputStyle: 'compressed',
            src: '**/*.scss',
            ext: '.css',
            flatten: true,
            extDot: 'last'
        }
    },
    watch: {
        config: {
            files: [ 'config/*.json' ],
            tasks: [ 'client-config-file:create' ]
        },
        sass: {
            files: [ 'app/views/styles/**/*.scss', 'widget/**/*.scss', '!app/views/styles/component/_system_variables.scss' ],
            tasks: [ 'sass' ],
            options: {
                spawn: false,
                livereload: true
            }
        },
        jade: {
            files: [ 'app/views/**/*.pug' ],
            options: {
                spawn: false,
                livereload: true
            }
        },
        language: {
            files: [ 'app/views/**/*.pug', 'app/controllers/**/*.js', 'app/models/**/*.js', 'public/js/src/**/*.js' ],
            tasks: [ 'shell:translation', 'i18next' ]
        },
        js: {
            files: [ 'public/js/src/**/*.js', 'widget/**/*.js' ],
            tasks: [ 'js-dev' ],
            options: {
                spawn: false,
                livereload: true
            }
        }
    },
    shell: {
        translation: {
            command: [
                'cd locales',
                'gulp',
                'cd ..'
            ].join( '&&' )
        },
        ie11polyfill: {
            command: [
                'mkdir -p public/js/build && curl "https://polyfill.io/v3/polyfill.min.js?ua=ie%2F11.0.0&features=es2015%2Ces2016%2Ces2017%2Ces2018%2Cdefault-3.6%2Cfetch%2CNodeList.prototype.forEach" -o "public/js/build/ie11-polyfill.min.js"',
                'cp -f node_modules/enketo-core/src/js/obscure-ie11-polyfills.js public/js/build/obscure-ie11-polyfills.js'
            ].join( '&&' )
        },
        'clean-css': {
            command: 'rm -f public/css/*'
        },
        'clean-locales': {
            command: 'find locales -name "translation-combined.json" -delete && rm -fr locales/??'
        },
        'clean-js': {
            command: 'rm -f public/js/build/* && rm -f public/js/*.js && rm -f public/temp-client-config.json'
        },
        rollup: {
            command: 'npx rollup --config'
        },
        babel: {
            command: bundles
                .map( bundle => `npx babel ${bundle} --out-file ${bundle.replace('-bundle.', '-ie11-temp-bundle.')}` )
                .join( '&&' )
        },
        browserify: {
            command: bundles
                .map( bundle => `npx browserify node_modules/enketo-core/src/js/workarounds-ie11.js ${bundle.replace('-bundle.', '-ie11-temp-bundle.')} -o ${bundle.replace('-bundle.', '-ie11-bundle.')}` )
                .concat( [ 'rm -f public/js/build/*ie11-temp-bundle.js' ] )
                .join( '&&' )
        }
    },
    jsbeautifier: {
        test: {
            src: JS_INCLUDE,
            options: {
                config: './.jsbeautifyrc',
                mode: 'VERIFY_ONLY'
            }
        },
        fix: {
            src: JS_INCLUDE,
            options: {
                config: './.jsbeautifyrc'
            }
        }
    },
    eslint: {
        all: JS_INCLUDE,
    },
    // test server JS
    mochaTest: {
        all: {
            options: {
                reporter: 'dot'
            },
            src: [ 'test/server/**/*.spec.js' ]
        },
        account: {
            src: [ 'test/server/account-*.spec.js' ]
        }
    },
    // test client JS
    karma: {
        options: {
            singleRun: true,
            reporters: [ 'dots' ],
            configFile: 'test/client/config/karma.conf.js'
        },
        headless: {
            browsers: [ 'ChromeHeadless' ]
        },
        browsers: {
            browsers: [ 'Chrome', 'ChromeCanary', 'Firefox', 'Opera' /*,'Safari'*/ ],
        }
    },
    terser: {
        options: {
            // https://github.com/enketo/enketo-express/issues/72
            keep_classnames: true,
        },
        all: {
            files: bundles
                .concat( bundles.map( bundle => bundle.replace( '-bundle.', '-ie11-bundle.' ) ) )
                .map( bundle => [ bundle.replace( '.js', '.min.js' ), [ bundle ] ] )
                .reduce( ( o, [ key, value ] ) => {
                    o[ key ] = value;
                    return o;
                }, {} )
        },
    },
    env: {
        develop: {
            NODE_ENV: 'develop'
        },
        test: {
            NODE_ENV: 'test'
        },
        production: {
            NODE_ENV: 'production'
        }
    },
    i18next: {
        locales: {
            cwd: 'locales/src/',
            expand: true,
            src: [ '*/' ],
            include: [ '**/translation.json', '**/translation-additions.json' ],
            rename( dest, src ) {
                return `${dest + src}translation-combined.json`;
            },
            dest: 'locales/build/'
        }
    }
} );

grunt.registerTask( 'client-config-file', 'Temporary client-config file', task => {
    const CLIENT_CONFIG_PATH = 'public/js/build/client-config.js';
    if ( task === 'create' ) {
        const config = require( './app/models/config-model' );
        grunt.file.write( CLIENT_CONFIG_PATH, `export default ${JSON.stringify( config.client )};` );
        grunt.log.writeln( `File ${CLIENT_CONFIG_PATH} created` );
    } else if ( task === 'remove' ) {
        grunt.file.delete( CLIENT_CONFIG_PATH );
        grunt.log.writeln( `File ${CLIENT_CONFIG_PATH} removed` );
    }
} );

grunt.registerTask( 'system-sass-variables', 'Creating _system_variables.scss', () => {
    const SYSTEM_SASS_VARIABLES_PATH = 'app/views/styles/component/_system_variables.scss';
    const config = require( './app/models/config-model' );
    grunt.file.write( SYSTEM_SASS_VARIABLES_PATH, `$base-path: "${config.server[ 'base path' ]}";` );
    grunt.log.writeln( `File ${SYSTEM_SASS_VARIABLES_PATH} created` );
} );

grunt.registerTask( 'widgets', 'generate widget reference files', () => {
    const WIDGETS_JS_LOC = 'public/js/build/';
    const WIDGETS_JS = `${WIDGETS_JS_LOC}widgets.js`;
    const WIDGETS_SASS_LOC = 'app/views/styles/component/';
    const WIDGETS_SASS = `${WIDGETS_SASS_LOC}_widgets.scss`;
    const PRE = '// This file is automatically generated with `grunt widgets`\n\n';
    const widgets = require( './app/models/config-model' ).server.widgets;
    const coreWidgets = require( './public/js/src/module/core-widgets' );
    const paths = Object.keys( widgets ).map( key => coreWidgets[ widgets[ key ] ] || widgets[ key ] );
    let num = 0;
    let content = PRE + paths.map( p => {
        if ( grunt.file.exists( WIDGETS_JS_LOC, `${p}.js` ) ) {
            num++;
            return `import w${num} from '${p}';`;
        } else {
            return `//${p} not found`;
        }
    } ).join( '\n' ) + `\n\nexport default [${[...Array(num).keys()].map(n => 'w'+(n+1)).join(', ')}];`;
    grunt.file.write( WIDGETS_JS, content );
    grunt.log.writeln( `File ${WIDGETS_JS} created` );
    content = `${PRE +
paths.map( p => {
    p = path.join( '../', p );
    return grunt.file.exists( WIDGETS_SASS_LOC, `${p}.scss` ) ? `@import "${p}"` : `//${p} not found`;
} ).join( ';\n' )};`;
    grunt.file.write( WIDGETS_SASS, content );
    grunt.log.writeln( `File ${WIDGETS_SASS} created` );
} );


grunt.registerTask('w', ['watch']);
grunt.registerTask( 'default', [ 'locales', 'widgets', 'css', 'js-ie11', 'terser' ] );
grunt.registerTask( 'locales', [ 'shell:clean-locales', 'i18next' ] );
grunt.registerTask( 'js', [ 'shell:clean-js', 'client-config-file:create', 'widgets', 'shell:rollup' ] );
grunt.registerTask( 'js-dev', [ 'js' ] );
grunt.registerTask( 'js-ie11', [ 'js', 'shell:ie11polyfill', 'shell:babel', 'shell:browserify' ] );
grunt.registerTask( 'css', [ 'shell:clean-css', 'system-sass-variables:create', 'sass' ] );
grunt.registerTask( 'test', [ 'env:test', 'js', 'css', 'mochaTest:all', 'karma:headless', 'jsbeautifier:test', 'eslint' ] );
grunt.registerTask( 'test-browser', [ 'env:test', 'css', 'client-config-file:create', 'karma:browsers' ] );
grunt.registerTask( 'develop', [ 'env:develop', 'i18next', 'js-dev', 'css', 'concurrent:develop' ] );
grunt.registerTask( 'develop-ie11', [ 'env:develop', 'i18next', 'js-ie11', 'css', 'concurrent:develop' ] );
grunt.registerTask( 'test-and-build', [ 'env:test', 'mochaTest:all', 'karma:headless', 'env:production', 'default' ] );};

当我运行 grunt watch 时,它只会在等待模式下继续运行并卡在那里?但我希望 grunt watch 能够正常工作,因为它可以让我在开发模式下工作。现在在我的项目中发生的事情是我必须一次又一次地运行 grunt 命令来构建项目以查看小的更改,这需要太多时间?我是新来的咕噜声。我想在快速/开发模式下工作,并希望在 grunt 文件中启用热重载功能以及 grunt watch。请提出一些解决方案。

4

0 回答 0