/** * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. */ /* eslint-env node */ const path = require( 'path' ); const fs = require( 'fs' ); const webpack = require( 'webpack' ); const { bundler, styles } = require( '@ckeditor/ckeditor5-dev-utils' ); const CKEditorWebpackPlugin = require( '@ckeditor/ckeditor5-dev-webpack-plugin' ); const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' ); const UglifyJsWebpackPlugin = require( 'uglifyjs-webpack-plugin' ); const webpackProcesses = new Map(); module.exports = function snippetAdapter( data ) { if ( !data.snippetSource.js ) { throw new Error( `Missing snippet source for "${ data.snippetPath }".` ); } const snippetConfig = readSnippetConfig( data.snippetSource.js ); const outputPath = path.join( data.outputPath, data.snippetPath ); const webpackConfig = getWebpackConfig( { entry: data.snippetSource.js, outputPath, language: snippetConfig.language, production: data.options.production } ); let promise; // See #530. if ( webpackProcesses.has( outputPath ) ) { promise = webpackProcesses.get( outputPath ); } else { promise = runWebpack( webpackConfig ); webpackProcesses.set( outputPath, promise ); } return promise .then( () => { const wasCSSGenerated = fs.existsSync( path.join( outputPath, 'snippet.css' ) ); const cssFiles = [ path.join( data.basePath, 'assets', 'snippet-styles.css' ) ]; // CSS may not be generated by Webpack if a snippet's JS file didn't import any SCSS files. if ( wasCSSGenerated ) { cssFiles.unshift( path.join( data.relativeOutputPath, data.snippetPath, 'snippet.css' ) ); } // If the snippet is a dependency of a parent snippet, append JS and CSS to HTML and save to disk. if ( data.isDependency ) { let htmlFile = fs.readFileSync( data.snippetSource.html ).toString(); if ( wasCSSGenerated ) { htmlFile += ''; } htmlFile += ''; fs.writeFileSync( path.join( outputPath, 'snippet.html' ), htmlFile ); } return { html: fs.readFileSync( data.snippetSource.html ), assets: { js: [ path.join( data.relativeOutputPath, data.snippetPath, 'snippet.js' ) ], css: cssFiles }, dependencies: snippetConfig.dependencies }; } ); }; function getWebpackConfig( config ) { const plugins = [ new MiniCssExtractPlugin( { filename: 'snippet.css' } ), new CKEditorWebpackPlugin( { language: config.language || 'en' } ), new webpack.BannerPlugin( { banner: bundler.getLicenseBanner(), raw: true } ) ]; const minimizer = []; if ( config.production ) { minimizer.push( new UglifyJsWebpackPlugin( { sourceMap: true, uglifyOptions: { output: { comments: /^\**!/ } } } ) ); } return { mode: config.production ? 'production' : 'development', devtool: 'source-map', entry: config.entry, output: { path: config.outputPath, filename: 'snippet.js' }, optimization: { minimizer }, plugins, // Configure the paths so building CKEditor 5 snippets work even if the script // is triggered from a directory outside ckeditor5 (e.g. multi-project case). resolve: { modules: getModuleResolvePaths() }, resolveLoader: { modules: getModuleResolvePaths() }, module: { rules: [ { test: /\.svg$/, use: [ 'raw-loader' ] }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: styles.getPostCssConfig( { themeImporter: { themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' ) }, minify: config.production } ) } ] } ] } }; } function runWebpack( webpackConfig ) { return new Promise( ( resolve, reject ) => { webpack( webpackConfig, ( err, stats ) => { if ( err ) { reject( err ); } else if ( stats.hasErrors() ) { reject( new Error( stats.toString() ) ); } else { resolve(); } } ); } ); } function getModuleResolvePaths() { return [ path.resolve( __dirname, '..', '..', 'node_modules' ), 'node_modules' ]; } function readSnippetConfig( snippetSourcePath ) { const snippetSource = fs.readFileSync( snippetSourcePath ).toString(); const configSourceMatch = snippetSource.match( /\n\/\* config ([\s\S]+?)\*\// ); if ( !configSourceMatch ) { return {}; } return JSON.parse( configSourceMatch[ 1 ] ); }